单调栈及模板
1.单调栈的应用
单调栈的应用是非常有限的,一般只适用于如下的模型:
给定一个序列,对于序列中的每一个数,找到这个数左边/右边离它最近的比它大/小的数是谁?如果找不到,返回-1或其他操作。
如果某一个问题,满足上述的模型,那么我们就可以用单调栈来进行解决。

例如,我们可以通过如上的案例,来求得:一个序列(3 4 2 7 5 )中,对于每一个数,左边离它最近的且比它小的数是谁,如果不存在,则返回-1。
2. 暴力解法分析

对于上述问题,我们可以采用如上的暴力算法来进行求解。
但是,对于上述的做法,时间复杂度很高,是O(n²)。因此,我们可以使用单调栈来进行优化。
3. 单调栈的过程
对于上述的暴力解法,我们可以运用一个栈来进行等价化。
具体来说,每当i往后进行移动时,i之前的元素都会存入到栈中。例如,当遍历到元素ai时,栈中会存放a1,a2,...,ai-1(其中a1在栈底,ai-1在栈顶)。当寻找离ai最近的且比它小的元素时,从栈顶到栈底遍历,找到第一个满足条件的元素即为答案。
但是,对于上述的做法,时间复杂度仍是没有改变。那么我们如何从上述的做法中提取出一些性质,来达到优化的目的呢?
根据上述的做法,我们可以发现如下性质:
1. 对于栈中的元素,如果存在两个元素ax和ay, 满足:ax >= ay 且 x < y。(实际上,不严格来说,ax和ay是一对逆序)那么,对于上述的条件(离ai最近的且比它小的元素)话,ax永远不会作为答案输出。(因为,ay比ax更好)
2. 因此,对于上述的性质,我们可以将栈中所有类似于ax这样的元素删掉。删掉之后,我们不难发现,栈中的元素均满足严格单调递增这样的性质。这也是单调栈这个数据结构的由来。
3. 根据上述的结论,我们可以得出单调栈的过程如下:
首先,我们以ai为基准,要寻找离ai左边最近的且比它小的元素。
1. 我们从栈顶开始遍历,如果栈顶元素比它小,由于栈中均是满足单调递增这个性质,因此栈顶及之后的元素均比它小,因此栈顶就是答案,且把ai放入到栈顶中。
2.如果栈顶元素比它大,那么栈顶元素永远不会作为答案进行输出。(为什么?假设,我们要考察ai+1这个元素,那么如果栈顶元素和ai均比ai+1要小,且栈顶元素大于等于ai,那么答案一定是ai而不是栈顶元素。所以,根据上述情况栈顶元素永远都不会作为答案输出。)因此把栈顶元素删掉,继续查看栈顶元素,直到找到第一个比它小的数为止。那么,此时就找到了答案,并将ai放入到栈顶中即可。
3.对于其他的数也是如此。
这样的话,我们就利用了单调栈来优化了问题。
因此,对于这样的问题,我们可以得出一个结论:
如果,题目要求找到每个数左边离它最近的且比它小的数。
答案:那么,我们可以从左往右遍历,如果栈顶元素比当前数大或相等,那么删掉栈顶元素即可。
如果,题目要求找到每个数左边离它最近的且比它大的数。
答案:那么,我们可以从左往右遍历,如果栈顶元素比当前数小或相等,那么删掉栈顶元素即可。
如果,题目要求找到每个数右边离它最近的且比它小的数。
答案:那么,我们可以从右往左遍历,如果栈顶元素比当前数大或相等,那么删掉栈顶元素即可。
如果,题目要求找到每个数右边离它最近的且比它大的数。
答案:那么,我们可以从右往左遍历,如果栈顶元素比当前数小或相等,那么删掉栈顶元素即可。
我们可以分析一下,经过单调栈优化的时间复杂度。我们可以发现,数组中的所有元素最多只会进栈一次,出栈一次。因此,加起来最多只会有2n次操作。因此,时间复杂度就是O(n)。
4. 单调栈模板
int tt = 0;
for (int i = 1; i <= n; i ++ )
{
while (tt && check(stk[tt], i)) tt -- ;
stk[ ++ tt] = i;
}
5. 例题
https://www.acwing.com/problem/content/832/
#include <iostream>
#include <cstdio>
using namespace std;
int stack[100010];
int tt = 0;
int main(){
int n;
scanf("%d",&n);
for(int i=0;i<n;i++){
int x;
scanf("%d",&x);
while(tt && stack[tt] >= x){
tt--;
}
if(tt){
printf("%d ",stack[tt]);
}else{
printf("-1 ");
}
stack[++tt] = x;
}
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岁的心里话
· 按钮权限的设计及实现