单调队列需存下标而非值,删头保窗口范围(deque[0]

Go 语言里没有内置单调队列,但用 slice + container/list 或纯切片模拟都能高效实现;关键不是“怎么写”,而是“在哪删、何时删、删什么”——多数人卡在边界逻辑和索引失效上。
为什么不用 container/list 直接存值?
很多人一上来就用 list.List 存数值,结果发现无法快速访问队首/队尾的下标,导致滑动窗口类问题(如 maxSlidingWindow)没法做索引剔除。单调队列真正需要维护的是「下标」,不是值本身。
- 存下标才能判断队首元素是否已滑出窗口(
deque[0] ) - 值只用于比较大小(
nums[deque[len(deque)-1]] ),决定是否弹尾 -
container/list的迭代和随机访问开销大,不如切片直接用deque[0]和deque[len(deque)-1]
用 []int 模拟双端队列时,删头删尾的条件是什么?
核心就两条:删头为保窗口范围,删尾为保单调性。顺序不能反,且必须用 (不是 <code>)来维持「非严格」单调。
-
删头(出队):
if len(deque) > 0 && deque[0] → 队首下标已不在 <code>[i-k+1, i]范围内 -
删尾(维护递减):
for len(deque) > 0 && nums[deque[len(deque)-1]] → 弹掉所有 ≤ 当前值的尾部下标 - 插入当前下标
i到队尾 - 队首
deque[0]即为窗口最大值对应下标(从第k-1个索引开始有效)
常见错误:越界访问、索引未更新、误判空队列
这些错误往往在窗口刚启动(i )或数据全相等时暴露:
- 删头前不检查
len(deque) > 0→panic: index out of range - 删尾循环里用
nums[deque[len(deque)-1]] (少了个 <code>=)→ 相同值堆积,破坏单调性,结果偏小 - 把
deque当成值容器,直接append(deque, nums[i])→ 后续所有下标计算全错 - 忘记在
i >= k-1后才记录答案 → 结果长度少k-1个
单调队列的复杂点不在结构本身,而在于每个操作都要同步维护「下标有效性」和「值序关系」;一旦某个下标被误留,后续所有最大值都会漂移。动手前先手写两轮滑动过程,盯住 deque 里存的是哪几个下标、对应值是多少、为什么该删不该删——比抄代码管用得多。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











