§1
题目描述
给数组和窗口大小 k,返回每个窗口里的最大值。
nums = [1,3,-1,-3,5,3,6,7], k=3
输出 = [3,3,5,5,6,7]
§2
思路解析动画文字版
关键不是背模板,而是看懂为什么这题适合单调队列。
1. i=0 纳入 1,下标 0 入队:队列存下标,不存值——这样能判断队头是否已滑出窗口。
2. i=1 纳入 3,弹掉队尾更小的 0(值1):新元素更大,就把队尾比它小的全弹掉——维持递减。
3. i=2 纳入 -1,直接入队尾:窗口刚满 k=3:队头下标对应的值就是答案。
4. i=3 纳入 -3,窗口右移,队头仍给最大:输出累计 [3,3]。
5. i=4 纳入 5,比队里全大 → 弹空,只剩 4:两种 while 要分清:先弹「滑出窗口的队头」,再弹「比新数小的队尾」。
6. i=5 纳入 3,入队尾,队头仍是 5:输出累计 [3,3,5,5]。
7. i=6 纳入 6,弹掉 3、5,只剩 6:输出累计 [3,3,5,5,6]。
8. i=7 纳入 7,弹掉 6,每个窗口都 O(1) 取最大:全程每个下标进队出队各一次 → 总体 O(n)。
把这句话记住,下次遇到同类题,就能更快选出方向。
迁移阶梯:把这题练到能复述后,再去同类题里迁移:先复用状态定义,再调整边界条件。
边界三连:边界三连:极端输入先过一遍。
几个高频追问,记住答法。
§3
参考代码
from collections import dequeclass Solution: def maxSlidingWindow(self, nums, k): q = deque() ans = [] for i, x in enumerate(nums): while q and q[0] <= i - k: q.popleft() while q and nums[q[-1]] <= x: q.pop() q.append(i) if i >= k - 1: ans.append(nums[q[0]]) return ans看懂代码不等于写得出。盖住上面,自己默写一遍试试。卡在哪一行说不清,就点右下角问小欧。
§4
复杂度
- 时间复杂度:O(n),每个核心状态按算法要求处理固定次数
- 空间复杂度:O(k),只保存必要的辅助结构或递归栈
§5
可套用的代码模板
模板不是死背,而是提醒你写代码前先把状态、转移和边界排好。
# 单调队列 通用检查表# 1. 定义状态/指针/容器# 2. 每轮只做一个清晰动作# 3. 更新答案并处理边界§6
易错点
✗ 错误写法:每个窗口都重新 max
✓ 正确写法:用单调队列维护候选最大值
重新扫描会 O(nk)
✗ 错误写法:只按样例推代码
✓ 正确写法:先写清状态含义和边界条件
样例太少,隐藏用例专打边界
✗ 错误写法:变量名和动画不一致
✓ 正确写法:代码变量沿用动画里的核心名字
学习时最怕脑内维护两套概念
§
面试追问把动画讲成自己的话
追问为什么单调队列是 O(n)?
每个元素最多入队、出队各一次,总共 O(n);比每个窗口求最大(O(nk))快得多。
追问队列为什么单调递减?
新元素若比队尾大,队尾那些更早更小的永远不可能再当最大,直接弹掉。
追问和用堆比?
堆 O(n log k) 且要处理过期元素;单调队列 O(n) 更优,是本题标准解。
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
下一题 · 滑动窗口 7/7
→找到字符串中所有字母异位词
LeetCode 438 · 中等 · 沿着 滑动窗口 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
299道动画图解
37节语音讲解
28课数据结构
¥0.27折合 / 天
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
¥99 开通年卡 →
想成体系刷透这类套路?去图解算法专题