单调队列及模板
1.单调队列的应用场景
单调队列的应用场景也比较单一,主要围绕着如下问题进行展开:
求滑动窗口中的最大值/最小值。
2.暴力做法分析
我们可以用队列来维护一个滑动窗口。在窗口的滑动过程中,实际上就是在往队列中添加/删除元素的过程。(具体来说,当窗口往右移动时,实际上就是在队尾中添加一个元素,在队头删除一个元素的过程。)在算法的执行过程中,队列里面始终保存当前窗口中的元素。
那么,对于上述问题的暴力做法是什么呢?我们可以每次遍历队列当中的元素,进而找到最大值和最小值即可。这样的话,就找到了滑动窗口中的最大值/最小值。
因此,对于上述的暴力做法,如果滑动窗口的长度为k,那么遍历一遍,时间复杂度就是O(k)。再加上滑动窗口的滑动过程,每个元素最多都是进队一次,出队一次。因此,滑动窗口本身滑动过程的时间复杂度就是O(n)。由于滑动窗口每滑动一次,就需要将窗口遍历一遍,因此时间复杂度就是O(nk)。
3.单调队列的执行过程

我们以上图的滑动窗口来进行举例。
我们可以发现,当我们求滑动窗口的最小值时,由于当前窗口中3和-1均在-3的左边(代表在窗口的滑动过程中,3和-1均比-3要更早的出队),且比-3要大(代表只要-3在窗口中,这两个数字永远都不会被当作答案来进行输出)。因此,满足以上两个条件的3和-1就是没有用的元素(与-3构成了逆序对),应当进行删除。
因此,根据上述例子,我们可以发现:
只要在队列中存在满足上述条件的情况(ax >= ay 且 x < y),我们就应该把没有用的元素(ax)进行删除。这样的话,当删除之后,队列里面的元素均是满足严格单调递增的,这也是单调队列这个名称的由来。并且,当我们求滑动窗口的最小值时,由于队列当中的元素都是严格单调递增的,因此队头元素即可满足要求。
如果求得是滑动窗口中的最大值,那么队列当中的元素应满足严格单调递减这样的性质。
根据上述算法,我们如何知道队列在什么时候出队呢?
在这道题中,i始终指向队列的尾部,k代表窗口的长度,并且队列中存储的是值对应的下标,而不是值本身。因此,我们只需要判断:当下标不在i-k+1~i这个区间内,那么这个下标所对应的值就不在窗口中,此时就需要出队了。
4.单调栈和单调队列的共性
对于单调栈和单调队列,我们可以发现:
1. 都是先通过栈和队列进行暴力求解。
2. 在暴力求解中寻找单调性,进一步实现优化。
3. 在进行优化的过程中,我们可以发现栈/队列中的元素均满足严格单调递增或递减。这样的话,如果我们想寻找栈/队列中的最大值/最小值,我们直接找端点即可。如果我们想要寻找栈/队列中的某一个元素,那么我们可以利用二分法寻找即可。
5. 单调队列模板
int hh = 0, tt = -1;
for (int i = 0; i < n; i ++ )
{
while (hh <= tt && check_out(q[hh])) hh ++ ;
while (hh <= tt && check(q[tt], i)) tt -- ;
q[ ++ tt] = i;
}
6.单调队列例题
https://www.acwing.com/problem/content/156/
#include <iostream>
#include <cstdio>
using namespace std;
int a[1000010],q[1000010];
int hh = 0,tt = -1;
int main(){
int n,k;
scanf("%d %d",&n,&k);
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
}
for(int i=0;i<n;i++){
while(hh <= tt && q[hh] < i-k+1){
hh++;
}
while(hh <= tt && a[q[tt]] >= a[i]){
tt--;
}
q[++tt] = i;
if(i >= k-1){
printf("%d ",a[q[hh]]);
}
}
printf("\n");
hh = 0,tt = -1;
for(int i=0;i<n;i++){
while(hh <= tt && q[hh] < i-k+1){
hh++;
}
while(hh <= tt && a[q[tt]] <= a[i]){
tt--;
}
q[++tt] = i;
if(i >= k-1){
printf("%d ",a[q[hh]]);
}
}
return 0;
}
作者:gao79138
链接:https://www.acwing.com/
来源:本博客中的截图、代码模板及题目地址均来自于Acwing。其余内容均为作者原创。
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现