单调队列思路:
0. 队列存储的是元素下标
1. 遍历数组元素
2. 维护队列:
队列不为空并且当前遍历元素 >= 队尾元素,向前压,比它小的全部被压扁了(删除了),直至队列为空或者遇到比它大的元素,停止。
4. 该元素下标入队
5. 计算窗口左边界left
6. 判断队首元素是否需要维护,如果 队首元素的下标 < left 说明该元素已经不在窗口内,可以从队列中清除
7. 将窗口内的最大值存入数组(这里窗口内的最大值也即是队首元素)
8. 返回操作1,直至退出循环
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
int[] res = new int[nums.length - k + 1]; // 窗口个数,存结果
LinkedList<Integer> queue = new LinkedList<>(); // 单调队列,存元素下标
// 遍历,right表示滑动窗口右边界
for(int right = 0; right < nums.length; right++) {
// 如果队列不为空且当前考察元素大于等于队尾元素,则移除队尾元素。
// 直到,队列为空或当前考察元素小于新的队尾元素
while (!queue.isEmpty() && nums[right] >= nums[queue.peekLast()]) {
queue.removeLast();
}
// 元素下标入队
queue.addLast(right);
// 计算窗口左边界
int left = right - k +1;
// 当队首元素的下标 < 窗口左边界left:
// 表示队首元素已经不再滑动窗口内,不用维护该元素,将其从队首移除
if (queue.peekFirst() < left) {
queue.removeFirst();
}
// 判断窗口是否形成。当 right + 1 >= k时,窗口形成
// 此时,队首元素为 该窗口内 最大值
if (right +1 >= k) {
res[left] = nums[queue.peekFirst()];
}
}
return res;
}
}
复杂度:
时间:O(n)
空间:O(k) 队列维护的窗口大小