用 双端队列(Deque) 维护"可能成为窗口最大值"的候选下标,
队头始终是当前窗口最大值,
每次右移窗口时:
- 弹出队头 过期 的下标(< left)
- 从队尾剔除 ≤ 新元素的下标
- 把新元素下标入队尾
- 记录队头值即可
时间 O(n) ,空间 O(k)。
代码(int[] 版,可直接跑)
java
import java.util.*;
public class SlidingWindowMax {
// 返回每个窗口的最大值列表
public static List<Integer> maxSlidingWindow(int[] nums, int k) {
List<Integer> ans = new ArrayList<>();
Deque<Integer> deq = new ArrayDeque<>(); // 存下标,单调递增
for (int i = 0; i < nums.length; i++) {
// 1. 弹出队头过期下标
while (!deq.isEmpty() && deq.peek() < i - k + 1) {
deq.poll();
}
// 2. 从队尾剔除 ≤ 当前值的候选
while (!deq.isEmpty() && nums[deq.peekLast()] <= nums[i]) {
deq.pollLast();
}
// 3. 当前下标入队
deq.offer(i);
// 4. 窗口形成后记录答案
if (i >= k - 1) {
ans.add(nums[deq.peek()]);
}
}
return ans;
}
/* ---------- 测试 ---------- */
public static void main(String[] args) {
int[] nums = {1, 3, -1, -3, 5, 3, 6, 7};
int k = 3;
System.out.println(maxSlidingWindow(nums, k)); // [3, 3, 5, 5, 6, 7]
}
}
复杂度
- 时间 :每个元素最多入队/出队一次 → O(n)
- 空间 :双端队列长度 ≤ k → O(k)
一句话记忆
"队头永远是当前窗口最大值,队尾单调递减踢小弟,过期下标及时扔 "------这就是滑动窗口最大值的 单调队列 套路。