239. 滑动窗口最大值
思路
-
双端队列的使用:我们使用双端队列来存储可能成为窗口最大值的元素索引。队列中的元素按从大到小排序。
-
维护队列:
- 移除不在当前窗口范围内的元素(从队列头部移除)
- 移除所有小于当前元素的队列元素(从队列尾部移除),因为它们不可能是当前或未来窗口的最大值
- 将当前元素添加到队列尾部
-
记录结果:当窗口完全形成时(即i >= k-1),队列头部的元素就是当前窗口的最大值。
遍历时,i从0开始,作为窗口的最右端,窗口区间为[i-k+1, i],当第一个完整窗口索引为[0, k-1],所以当i >= k-1时开始取队列中的最大值。
结果数组的长度,取决于,第一个完整窗口移动到最右端的次数,即从k-1移动到n-1,再加上第一个窗口的最大值个数,n-1-(k-1)+1=n-k+1。
复杂度分析
- 时间复杂度:O(n),每个元素被处理两次(一次添加,一次移除)
- 空间复杂度:O(k),双端队列最多存储k个元素
代码
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if (nums == null || nums.length == 0 || k <= 0) {
return new int[0];
}
int n = nums.length;
int[] res = new int[n - k + 1];
int resi = 0;
// 优先队列,用来保存可能是窗口最大值的元素索引
Deque<Integer> deque = new LinkedList<>();
for (int i = 0; i < n; i++) {
// 移出不在窗口内的索引,最先加入的最先移出,从头部开始
while (!deque.isEmpty() && deque.peekFirst() < i - k + 1) {
deque.pollFirst();
}
// 移出小于当前值的元素索引,因为该值不可能是当前窗口或未来窗口的最大值
while (!deque.isEmpty() && nums[deque.peekLast()] < nums[i]) {
// 为了保证队列中索引对应的元素是从大到小排列,从尾部开始
deque.pollLast();
}
// 添加当前元素索引到尾部
deque.offerLast(i);
// 当形成完整的窗口后,开始取最大值
if (i >= k-1) {
res[resi++] = nums[deque.peekFirst()];
}
}
return res;
}
}

浙公网安备 33010602011771号