給定一個數組 nums 和滑動窗口的大小 k,請找出所有滑動窗口裏的最大值。
示例:輸入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
輸出: [3,3,5,5,6,7]
解釋:
滑動窗口的位置 最大值[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
提示:
你可以假設 k 總是有效的,在輸入數組不爲空的情況下,1 ≤ k ≤ 輸入數組的大小。
本題採用雙端隊列的方法來完成,首先先介紹一下雙端隊列,Deque。這是一個接口,我們一般在使用的時候,都使用ArrayDeque,LinkedList,也就是說,一個是基於數組,一個是基於鏈表。他和普通的隊列最大的區別就在於,雙端隊列從兩端都可以進行隊列的操作。
解題步驟:本題的目的是用長度爲k的數組進行入隊出隊的操作,直到滑到最右邊,然後將每次滑動產生的新數組內的最大值,存儲到一個新的數組中,最後返回這個數組。
解題思路:我們可以將這個滑動的數組,翻譯成一個雙端隊列。將每次將來進隊的數字和隊列最右邊(隊尾)進行比較,如果新數字大,就將隊尾進行出隊操作,新數進行入隊操作。那麼問題就來了,我們要如何知道新進來的數字,成爲雙向隊列對頭的時機呢,也可以說,我們如何讓窗口和雙向隊列裏面的數保持一致呢?這就可以用一個技巧。我們可以用隊列不去存儲value,而去存儲在nums裏面的下標,然後就可以判斷這個數實際的下標了。
public int[] maxSlidingWindow(int[] nums, int k) {
Deque<Integer> deque = new ArrayDeque<>();
if(nums.length==0){
return new int[0];
}
int arr[] = new int[nums.length-k+1];
for(int i = 0 ; i<nums.length ; i++){
if(!deque.isEmpty()&&deque.peekFirst()==i-k){
deque.removeFirst();
}
while(!deque.isEmpty()&&nums[deque.peekLast()]<nums[i]){
deque.removeLast();
}
deque.offerLast(i);
if(i>=k-1){
arr[i-k+1]=nums[deque.peek()];
}
}
return arr;
}