单调递增或单调减的栈,跟单调队列差不多,但是只用到它的一端,利用它可以用来解决一些ACM/ICPC和OI的题目,如RQNOJ 的诺诺的队列等。
单调栈是一种特殊的栈,栈内元素保存单调性
作用:
利用单调栈,可以找到向左/右遍历第一个比它小/大的元素的位置
以向左遍历第一个比它小的点为例:
我们要求左边最近的比a[i]小的点的位置,呢么我们栈中元素应该是要比a[i]小的,如果没有,呢么就没找到,就是0
- 判断栈中元素是否比a[i]大,如果大就一直弹出,直到空为止
- 如果栈为空,呢么标记左边没有比它小的元素,否则stack.top()就是向左遍历第一个比它小的点
- 压入a[i].
5
1 3 4 2 5
(1)1.size()==0不做 2. 0 3. 压入1
(2)1. 1<3 无需弹出 2. 1 3.压入3
(3)1. 3<4 无需弹出 2. 2 3.压入4
(4)1. 4>2,3>2 弹出4,弹出3 2.1 压入2
(5) 1. 2<5 2. 4 压入5
代码:
向左遍历第一个比它小的,呢么单调栈是正序的,sk.top()<a[i]
向左遍历第一个比它大的,呢么单调栈是正序的,sk.top()>a[i]
向右仅仅把遍历顺序改变即可
向左遍历第一个比它小的点:
#include<bits/stdc++.h>
#define MAXN 100005
using namespace std;
stack<int> sk;
int a[MAXN];
int ans[MAXN];
int main()
{
int n,x,y;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
{
while(sk.size()&&a[sk.top()]>=a[i])
sk.pop();
if(sk.empty())//左边没有,呢么就是0
ans[i]=0;
else
ans[i]=sk.top();
sk.push(i);
}
for(int i=1;i<=n;i++)
printf("%d\n",ans[i]);
return 0;
}
向左遍历第一个比它大的点:
for(int i=1;i<=n;i++)
{
while(sk.size()&&a[sk.top()]<=a[i])
sk.pop();
if(sk.empty())
ans[i]=0;
else
ans[i]=sk.top();
sk.push(i);
}
向右遍历第一个比它大的点:
for(int i=n;i>=1;i--)
{
while(sk.size()&&a[sk.top()]<=a[i])
sk.pop();
if(sk.empty())
ans[i]=0;
else
ans[i]=sk.top();
sk.push(i);
}
向右遍历第一个比它小的点:
for(int i=n;i>=1;i--)
{
while(sk.size()&&a[sk.top()]>=a[i])
sk.pop();
if(sk.empty())
ans[i]=0;
else
ans[i]=sk.top();
sk.push(i);
}
题目:https://blog.youkuaiyun.com/weixin_41183791/article/details/89431494
https://blog.youkuaiyun.com/weixin_41183791/article/details/89298010