持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,滑动窗口的最大值[单调双端队列] - 掘金 (juejin.cn)
前言
对于有序/连续子数组的最大最小问题,单调栈/队列/双端队列都是很好的记录小能手,记住这些大小值问题,就能降低时间复杂度,以空间换时间。
一、滑动窗口的最大值
二、单调双端队列ArrayDeque
A.idea
target:给定一个固定大小的窗口,从数组左边往右滑动,取每个窗口中的最大值。
M1:维持一个非严格单调递减队列,滑动一格,会有一个新元素和旧元素。
1-添加新元素,如果该元素比队尾小,直接入队,否则从队尾出队元素,直至队列为空或者队尾元素大于新元素;
2-移除旧元素,如果该元素比队首小,直接不管,否则从队首出队元素;
3-取每个窗口最大值,取队首值即可,它是单调队列中最大的值。
B.code
package everyday;
import java.util.ArrayDeque;
// 滑动窗口的最大值。
public class MaxSlidingWindow {
/*
target:给定一个固定大小的窗口,从数组左边往右滑动,取每个窗口中的最大值。
M1:维持一个非严格单调递减队列,滑动一格,会有一个新元素和旧元素。
添加新元素,如果该元素比队尾小,直接入队,否则从队尾出队元素,直至队列为空或者队尾元素大于新元素;
移除旧元素,如果该元素比队首小,直接不管,否则从队首出队元素;
取每个窗口最大值,取队首值即可,它是单调队列中最大的值。
*/
public int[] maxSlidingWindow(int[] nums, int k) {
int n = nums.length;
if (0 == n) return new int[]{};
// assert k > 0 && k < nums.length;
// 采用双端队列。
ArrayDeque<Integer> que = new ArrayDeque<>();
int begin = 0;
// 先将k - 1一个元素放进去。
while (begin < k - 1) {
while (!que.isEmpty() && que.peekLast() < nums[begin]) que.pollLast();
que.add(nums[begin++]);
}
int[] rs = new int[n - k + 1];
// 开始取出旧元素,添加新元素,取最大值。
for (int i = begin; i < n; i++) {
// 取旧元素。
int oldIdx = i - k;
if (oldIdx >= 0 && nums[oldIdx] == que.peek()) que.poll();
// 填新元素。
while (!que.isEmpty() && que.peekLast() < nums[i]) que.pollLast();
que.add(nums[i]);
// 取最大值加入数组。
rs[i - begin] = que.peek();
}
return rs;
}
}
总结
1)单调双端队列的应用场景与练习。
2)ArrayDeque双端队列。