classSolution{publicint[]maxSlidingWindow(int[] nums,int k){int n = nums.length;int[] result =newint[n - k +1];Deque<Integer> deque =newArrayDeque<>();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){
result[i - k +1]= nums[deque.peekFirst()];}}return result;}}
仅18行核心代码!
🎭 最易懂代码(注释版)
classSolution{publicint[]maxSlidingWindow(int[] nums,int k){int n = nums.length;int[] result =newint[n - k +1];// 结果数组Deque<Integer> window =newArrayDeque<>();// 存储索引的双端队列for(int i =0; i < n; i++){// 步骤1:移除超出窗口左边界的索引if(!window.isEmpty()&& window.peekFirst()< i - k +1){
window.pollFirst();}// 步骤2:维护单调递减特性// 移除所有比当前元素小的索引(它们不可能成为最大值)while(!window.isEmpty()&& nums[window.peekLast()]< nums[i]){
window.pollLast();}// 步骤3:添加当前元素索引
window.offerLast(i);// 步骤4:当窗口大小达到k时,记录最大值if(i >= k -1){
result[i - k +1]= nums[window.peekFirst()];}}return result;}}
🎬 可视化演示过程
示例1:nums = [1,3,-1,-3,5,3,6,7], k = 3
🔄 完整执行过程
步骤
i
当前元素
窗口状态
双端队列变化
结果
初始
-
-
数组
1
3
-1
-3
5
3
6
7
索引
0
1
2
3
4
5
6
7
deque = []
result = []
🎯 逐步执行详解
i=0: 处理元素 nums[0]=1
操作
队列状态
说明
检查左边界
deque = []
队列为空,无需移除
维护单调性
deque = []
队列为空,无需移除
添加索引
deque = [0]
添加索引0
检查窗口
i=0 < k-1=2
窗口未形成,不记录结果
当前状态:
数组
1
3
-1
-3
5
3
6
7
索引
0
1
2
3
4
5
6
7
窗口
🔲
i=1: 处理元素 nums[1]=3
操作
队列状态
说明
检查左边界
deque = [0]
索引0在范围内 0 >= 1-3+1=-1
维护单调性
deque = []
移除索引0,因为nums[0]=1 < nums[1]=3
添加索引
deque = [1]
添加索引1
检查窗口
i=1 < k-1=2
窗口未形成,不记录结果
当前状态:
数组
1
3
-1
-3
5
3
6
7
索引
0
1
2
3
4
5
6
7
窗口
🔲
🔲
i=2: 处理元素 nums[2]=-1
操作
队列状态
说明
检查左边界
deque = [1]
索引1在范围内 1 >= 2-3+1=0
维护单调性
deque = [1]
保持不变,因为nums[1]=3 > nums[2]=-1
添加索引
deque = [1, 2]
添加索引2
检查窗口
i=2 >= k-1=2
✅ 窗口形成!记录最大值
窗口1:[1, 3, -1] → 最大值 = nums[1] = 3
数组
1
3
-1
-3
5
3
6
7
索引
0
1
2
3
4
5
6
7
deque
✓
✓
窗口
🔲
🔲
🔲
i=3: 处理元素 nums[3]=-3
操作
队列状态
说明
检查左边界
deque = [1, 2]
索引1在范围内 1 >= 3-3+1=1
维护单调性
deque = [1, 2]
保持不变,因为nums[2]=-1 > nums[3]=-3
添加索引
deque = [1, 2, 3]
添加索引3
检查窗口
i=3 >= k-1=2
✅ 记录最大值
窗口2:[3, -1, -3] → 最大值 = nums[1] = 3
数组
1
3
-1
-3
5
3
6
7
索引
0
1
2
3
4
5
6
7
deque
✓
✓
✓
窗口
🔲
🔲
🔲
i=4: 处理元素 nums[4]=5
操作
队列状态
说明
检查左边界
deque = [2, 3]
移除索引1,因为1 < 4-3+1=2
维护单调性
deque = []
移除索引2,3,因为都比5小
添加索引
deque = [4]
添加索引4
检查窗口
i=4 >= k-1=2
✅ 记录最大值
窗口3:[-1, -3, 5] → 最大值 = nums[4] = 5
数组
1
3
-1
-3
5
3
6
7
索引
0
1
2
3
4
5
6
7
deque
✓
窗口
🔲
🔲
🔲
i=5: 处理元素 nums[5]=3
操作
队列状态
说明
检查左边界
deque = [4]
索引4在范围内 4 >= 5-3+1=3
维护单调性
deque = [4]
保持不变,因为nums[4]=5 > nums[5]=3
添加索引
deque = [4, 5]
添加索引5
检查窗口
i=5 >= k-1=2
✅ 记录最大值
窗口4:[-3, 5, 3] → 最大值 = nums[4] = 5
数组
1
3
-1
-3
5
3
6
7
索引
0
1
2
3
4
5
6
7
deque
✓
✓
窗口
🔲
🔲
🔲
i=6: 处理元素 nums[6]=6
操作
队列状态
说明
检查左边界
deque = [4, 5]
索引4在范围内 4 >= 6-3+1=4
维护单调性
deque = []
移除索引4,5,因为都比6小
添加索引
deque = [6]
添加索引6
检查窗口
i=6 >= k-1=2
✅ 记录最大值
窗口5:[5, 3, 6] → 最大值 = nums[6] = 6
数组
1
3
-1
-3
5
3
6
7
索引
0
1
2
3
4
5
6
7
deque
✓
窗口
🔲
🔲
🔲
i=7: 处理元素 nums[7]=7
操作
队列状态
说明
检查左边界
deque = [6]
索引6在范围内 6 >= 7-3+1=5
维护单调性
deque = []
移除索引6,因为nums[6]=6 < nums[7]=7
添加索引
deque = [7]
添加索引7
检查窗口
i=7 >= k-1=2
✅ 记录最大值
窗口6:[3, 6, 7] → 最大值 = nums[7] = 7
数组
1
3
-1
-3
5
3
6
7
索引
0
1
2
3
4
5
6
7
deque
✓
窗口
🔲
🔲
🔲
📊 执行结果总结
窗口
范围
元素
队列状态
最大值
1
[0,2]
[1, 3, -1]
[1, 2]
3
2
[1,3]
[3, -1, -3]
[1, 2, 3]
3
3
[2,4]
[-1, -3, 5]
[4]
5
4
[3,5]
[-3, 5, 3]
[4, 5]
5
5
[4,6]
[5, 3, 6]
[6]
6
6
[5,7]
[3, 6, 7]
[7]
7
最终结果:[3, 3, 5, 5, 6, 7] ✅
🧠 算法核心原理
💡 为什么使用双端队列?
队头维护最大值:队头索引对应的元素永远是当前窗口最大值
队尾处理新元素:新元素从队尾进入,移除比它小的无用元素
单调递减特性:确保队列中元素从大到小排列
🔍 关键操作解析
1️⃣ 移除超出窗口的索引
while(!deque.isEmpty()&& deque.peekFirst()< i - k +1){
deque.pollFirst();}