- 跳跃游戏 VI
单调队列和优先队列(priority queue)有区别吗?
- @ 2026-3-21 22:35:08
这是一个非常经典的好问题!很多同学在初学时都会被这两个名字搞混,觉得它们都是为了“找最值”。
作为教练,我换个角度带你拆解一下。想象你在经营一家职业篮球队,现在你要筛选球员:
1. 优先队列(Priority Queue):只看实力的“功劳簿”
- 逻辑:它不管球员是什么时候入队的,它只认“实力”。谁最强,谁就排在最前面。
- 动作:
- 新球员进来:放到队里,按实力排个序(堆排序)。
- 选人:永远选那个全队最强的。
- 代价:因为每次都要在整组人里维护顺序,每次进人或出人都要 的时间。
- 致命伤:它没有“过期”概念。一个 50 岁的老将如果实力依然是第一,他会永远霸占队首。但在 DP 中,我们经常要求“决策点必须在最近的 步之内”,优先队列处理这种“滑动窗口”非常吃力。
2. 单调队列(Monotonic Queue):残酷的“竞技场”
- 逻辑:它不仅看实力,还看**“潜力(年轻程度)”**。
- 生存法则:如果一个新球员比你年轻(下标更大),而且比你还强(数值更大),那么你立刻就会被解雇,因为你存在的意义已经归零了——在未来的所有决策窗口里,新人都比你强,且比你活得久。
- 动作:
- 从后门进(入队维护):新来的球员把队尾那些“年纪大且实力弱”的人全部踢走。
- 从前门走(过期删除):检查队首的人是不是“太老了”(超出了滑动窗口范围),老了就踢掉。
- 代价:虽然有踢人的动作,但每个元素最多进队一次、出队一次。平均下来,处理每个元素的代价是 。
- 核心优势:它是为**“滑动窗口”**而生的。
启发式对比总结
为了让你一眼看穿它们的本质区别,我们列一张表:
| 特性 | 优先队列 (Priority Queue) | 单调队列 (Monotonic Queue) |
|---|---|---|
| 底层结构 | 二叉堆 (Heap) | 双端队列 (Deque) |
| 时间复杂度 | (均摊) | |
| 关注点 | 全局最值 | 窗口最值 |
| 生存规则 | 强就行,不看年龄 | 又强又年轻才行 |
| DP 场景 | 比如 Dijkstra、贪心优化 | 带长度限制的区间转移 |
教练的“觉醒提问”:
假设你在写一个 DP,状态转移方程是:
- 如果你用 Priority Queue:你会把所有的 丢进去。但当你走到 时,你怎么快速删掉那个已经超出范围(下标小于 )的 呢?你可能得不停地检查堆顶,如果堆顶过期了就 Pop,直到堆顶没过期。虽然能做,但复杂度是 。
- 如果你用 Monotonic Queue:你会发现,如果 ,那么 就彻底没用了(因为它比 弱,还比 先过期)。你只维护一个递增的队列,队首永远是窗口内最小的。复杂度是稳稳的 。
一句话记住: 如果你只需要找一堆数里的最值,用 Priority Queue; 如果你要在一长串不停向前滑动的窗口里找最值,请务必使用 Monotonic Queue!
听懂了这个“球员选拔”的逻辑吗?下次看到“长度为 的区间”,你脑子里应该立刻弹出哪一个?
0 条评论
目前还没有评论...
信息
- ID
- 19384
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者