leetcode-cn.com/problems/sl…java
示例1:數組
輸入:nums = [1,3,-1,-3,5,3,6,7], k = 3 輸出:[3,3,5,5,6,7] 解釋: 滑動窗口的位置 最大值markdown
[1 3 -1] -3 5 3 6 7 3oop
1 [3 -1 -3] 5 3 6 7 3優化
1 3 [-1 -3 5] 3 6 7 5ui
1 3 -1 [-3 5 3] 6 7 5spa
1 3 -1 -3 [5 3 6] 7 6code
1 3 -1 -3 5 [3 6 7] 7orm
示例2:隊列
輸入:nums = [1], k = 1 輸出:[1]
示例3:
輸入:nums = [1,-1], k = 1 輸出:[1,-1]
示例4:
輸入:nums = [9,11], k = 2 輸出:[11]
示例 5:
輸入:nums = [4,-2], k = 2 輸出:[4]
提示:
1 <= nums.length <= 105 -104 <= nums[i] <= 104 1 <= k <= nums.length
思路:
題目內容比較好理解,就是滑動數組在滾動時返回每次滾動窗口內的最大值
初步設想:開始滾動時,維護當前窗口大小的一個數組,有序記錄最大值,在滾動時對移除值及移入值進行一個大小維護替換
- 大小維護:對有序 數組二分查找更新
- 設想更新:對當前窗口的大小數據構建一個大堆維護,當最大值移除時
設想2:找到當前滑動窗口最大值,在滾動超出當前滑動窗口以前,最大值都不會變(在沒有移入更大值以前)
在移除當前窗口最大值時,從新查找最大值
可以完成但效率低,超時
public static int[] maxSlidingWindow(int[] nums, int k) { //從0開始移動 int maxIndex = findMaxIndex(nums, 0, k); int length = nums.length; int moveStep = length - k+1; int[] maxNums = new int[moveStep]; maxNums[0] = nums[maxIndex]; for (int i = 1; i < moveStep; i++) { //移入的值爲 i+k-1 maxIndex = nums[maxIndex]>nums[i+k-1]?maxIndex:i+k-1; if (i>maxIndex) { maxIndex = findMaxIndex(nums,i,k+i); } maxNums[i] = nums[maxIndex]; } return maxNums; } public static int findMaxIndex(int[] nums, int start, int end) { int max = start; for (int i = start+1; i < end; i++) { max = nums[i]>=nums[max]? i:max;//由於向右移動,全部相等時取index更大的值能夠減小計算步驟 } return max; } 複製代碼
參考官方解:單調隊列
- 算是對個人方法的優化吧,元素 n-1與n 若是nums[n-1]<nums[n],那n-1在窗口中時,最大值必定不會爲它
- 按照這個性質來進行隊列的維護
package sj.shimmer.algorithm.m4_2021;
import java.util.Deque;
import java.util.LinkedList;
import sj.shimmer.algorithm.Utils;
/** * Created by SJ on 2021/4/23. */
class D86 {
public static void main(String[] args) {
Utils.logArray(maxSlidingWindow(new int[]{1,3,-1,-3,5,3,6,7},3));
Utils.logArray(maxSlidingWindow(new int[]{1},1));
Utils.logArray(maxSlidingWindow(new int[]{1,-1},1));
Utils.logArray(maxSlidingWindow(new int[]{9,11},2));
Utils.logArray(maxSlidingWindow(new int[]{4,-2},2));
}
public static int[] maxSlidingWindow(int[] nums, int k) {
int n = nums.length;
//雙端隊列存儲前k個元素的可永久移除的數據,嚴格的單調遞減
Deque<Integer> deque = new LinkedList<Integer>();
for (int i = 0; i < k; ++i) {
while (!deque.isEmpty() && nums[i] >= nums[deque.peekLast()]) {
deque.pollLast();
}
deque.offerLast(i);
}
int[] ans = new int[n - k + 1];
ans[0] = nums[deque.peekFirst()];
for (int i = k; i < n; ++i) {
while (!deque.isEmpty() && nums[i] >= nums[deque.peekLast()]) {
deque.pollLast();
}
deque.offerLast(i);
while (deque.peekFirst() <= i - k) {
deque.pollFirst();
}
ans[i - k + 1] = nums[deque.peekFirst()];
}
return ans;
}
}
複製代碼
優先隊列
我設想的解決方案,這裏用大根堆來解決了維護問題
單調隊列
參考方案:見上
分塊 + 預處理
數學知識,