给定一个数组 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
思路:
其实我们可以使用暴力来解决这个问题,但是问题就是它的时间复杂度会变成n*k
我们可以使用一个双端队列,DeQueue来解决,使求算最大值的时间变成O(1)
具体的思路就是:
- 在未形成窗口的时候:利用一个双端队列,在每次加入一个新的数的时候,就与队列后面的数进行比较,如果大于,就把后面的数删除。直到队列为空或者是说>=的时候,把这个数添加到队尾-=====》这是一个重点,因为在我们加入的时候,我们是从后往前比较的,我们要保证这个双端队列使单调递减的。
- 在形成窗口的时候,就需要多一步,判断就是队首是不是我们要淘汰的那个数,nums[i-k]—》我们会淘汰这个数,因为滑动窗口,每次滑动一个。
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if(nums.length==0)
return nums;
Deque<Integer> deque=new LinkedList<>();
int []res=new int[nums.length-k+1];
int index=0;
//未形成窗口的时候
for(int i=0;i<k;i++){
while(!deque.isEmpty()&&deque.peekLast()<nums[i])
deque.removeLast();
//重要点,因为我们是从后往前比较,所以应该是往后插入,而不是插入到前面frist
deque.addLast(nums[i]);
}
res[index++]=deque.peekFirst();
//形成窗口之后,开始遍历剩下的数
for(int i=k;i<nums.length;i++){
if(deque.peekFirst()==nums[i-k])
deque.removeFirst();
while(!deque.isEmpty()&&deque.peekLast()<nums[i])
deque.removeLast();
//
deque.addLast(nums[i]);
res[index++]=deque.peekFirst();
}
return res;
}
}