题目描述
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值。
运行结果
思路总结
之前牛客上是采用双指针加大顶堆实现的。但是会出现超时,无法通过
题解的思路是采用双端队列的方式(思想和实现一个求最大值的队列的时间为O(1)是一样的)
1.维持一个单调序列:即维持一个序列满足单调。(队列里存的是一个滑动窗口的情况)
入队规则:如果要加入的元素比队尾元素大,则移除队尾元素,直到小于队尾元素时,将该元素入队
出队规则:队头一直是当前队列的最大值。---当窗口右移时,如果窗口前移出的值和队头元素一致,则移除队头
最后滑动窗口的最大值一定是队头元素,直接入队即可
import java.util.*;
class Solution {
//双指针加大顶堆---超时
/*public int[] maxSlidingWindow(int[] nums, int k) {
int[] ans=new int[nums.length-k+1];
if(k <=0 || k > nums.length) return ans;
PriorityQueue<Integer> max_heap=new PriorityQueue<Integer>(new Comparator<Integer>(){
@Override
public int compare(Integer o1,Integer o2){
return o2-o1;
}
});
for(int i=0,j=k;j<=nums.length;i++,j++){
for(int m=i;m<j;m++){
max_heap.offer(nums[m]);
}
ans[i]=max_heap.peek();
max_heap.clear();
}
return ans;
}*/
//求最大值时间为O(1)的队列
public int[] maxSlidingWindow(int[] nums, int k) {
int len = nums.length;
if (len == 0) {
return nums;
}
int[] ans = new int[len - k + 1];
int ans_index = 0;
//我们需要维护一个单调递增的双向队列
Deque<Integer> deque = new LinkedList<>();
//先将第一个窗口的值按照规则入队
for (int i = 0; i < k; i++) {
while (!deque.isEmpty() && deque.peekLast() < nums[i]) {
deque.removeLast();
}
deque.offerLast(nums[i]);
}
//存到数组里,队头元素
ans[ans_index++] = deque.peekFirst();
//移动窗口
for (int j = k; j < len; j++) {
//对应咱们的红色情况,则是窗口的前一个元素等于队头元素
if (nums[j - k] == deque.peekFirst()) {
deque.removeFirst();
}
while (!deque.isEmpty() && deque.peekLast() < nums[j]) {
deque.removeLast();
}
deque.offerLast(nums[j]);
ans[ans_index++] = deque.peekFirst();
}
return ans;
}
}
京公网安备 11010502036488号