单调栈
顾名思义就是栈里的元素是单调的。
但是这个怎么使用呢?怎么就能是单调的呢?看下面的例题
题目
给定一个长度为N的整数数列,输出每个数左边第一个比它小的数,如果不存在则输出-1。
输入样例:
5
3 4 2 7 5
输出样例:
-1 3 -1 2 2
题目意思很容易理解
那么我们先来看暴力做法,每次取一个数,与前面的数比较
for(int i=0;i<n;i++)
{
for(int j=1;j=i;j++)
{
if(a[j]>=a[j-1])
{
break;
}
}
}
我们考虑最坏的情况,当序列为降序序列时,例如:
5
5 4 3 2 1
5的话不进循环
4的话与5比较
3与4和5比较
2与3、4和5进行比较
1与2、3、4和5进行比较
观察我们可以发现,我们就需要取出每个数,然后遍历一遍这个数之前的所有数。
时间复杂度为O(n^2),oj数据范围都是n<=1e5,评测机1s内运算数据量是1e8~1e9,我们对1e10的数据量是不能接受的,因此我们需要对做法进行优化。这个时候我们就引入单调栈。
以输入样例为例来模拟一下单调栈
3 4 2 7 5
我们顺序遍历,从前往后看
先看3,前面没有比他小的放入栈中
再看4,然后与栈顶元素比较,发现满足条件,那么输出栈顶元素,然后将4入栈
再看2,同样与栈顶元素比较,但是栈顶元素比2大,那么我们就需要pop出栈,然后再与栈顶元素比较,直到找到比2小的元素,或者是栈空时结束,然后我们需要判断栈是否为空,栈空就输出-1,栈不空那么就说明找到了比2小的元素,即输出栈顶元素,最后将2入栈
再看7,比较栈顶元素,小于栈顶元素,那么输入栈顶元素,入栈
最后看5,比较弹出栈顶元素,然后再比较,发现满足条件,输出栈顶元素
我们再看一下栈中元素的变化过程
3
3 4
2
2 7
2 5
这个时候就会发现栈中的元素是从栈底到栈顶是单调递增的。这也就是为什么叫做单调栈!!!
模板代码
#include<iostream>
using namespace std;
const int N=1e5+5;
int a[N],stk[N],n,tt=0;
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",a+i);
for(int i=0;i<n;i++)
{
while(tt&&a[i]<=stk[tt]) --tt;
if(tt) printf("%d ",stk[tt]);
else printf("-1 ");
stk[++tt]=a[i];
}
return 0;
}