单调栈:一种特殊的栈。在栈的「先进后出」规则基础上,要求「从 栈顶 到 栈底 的元素是单调递增(或者单调递减)」。其中满足从栈顶到栈底的元素是单调递增的栈,叫做「单调递增栈」。满足从栈顶到栈底的元素是单调递减的栈,叫做「单调递减栈」
1.单调递增栈
单调递增栈:只有比栈顶元素小的元素才能直接进栈,否则需要先将栈中比当前元素小的元素出栈,再将当前元素入栈。
这样就保证了:栈中保留的都是比当前入栈元素大的值,并且从栈顶到栈底的元素值是单调递增的。
单调递增栈的入栈、出栈过程如下:
假设当前进栈元素为 x,如果 x 比栈顶元素小,则直接入栈。
否则从栈顶开始遍历栈中元素,把小于 x 或者等于 x 的元素弹出栈,直到遇到一个大于 x 的元素为止,然后再把 x 压入栈中。栈内元素为下标
单调栈例题 :【模板】单调栈 - 洛谷
#include<iostream>
#include<stack>
using namespace std;
#define ll long long
const int N=3e6+5;
ll a[N],s1[N];
int main(){
stack<ll> s;
int n;
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=n;i>0;i--){
while(!s.empty()&&a[s.top()]<=a[i])
s.pop(); // <=是因为题目要求是第 i个元素后
if(s.empty()) s1[i]=0; //第一个大于a[i]的数
else s1[i]=s.top(); //因为我们是从后往前遍历的,所以如果等于的话也要弹出
s.push(i); //小于栈顶元素直接入栈
}
for(int i=1;i<=n;i++)
cout<<s1[i]<<" ";
cout<<endl;
}
如果插入时的栈为空,则说明右侧不存在比当前元素大的元素,就先存入栈中。如果后面有比当前元素大的,就把栈顶元素删除,把当前元素的下标入栈;如果比栈顶元素小就直接入栈,每次记录当前栈顶的值就为第一个大于 a[i]的值的下标,如果该元素没有被弹出栈,则说明右侧不存在比当前元素大的元素。
2.单调递减栈
单调递减栈:只有比栈顶元素大的元素才能直接进栈,否则需要先将栈中比当前元素大的元素出栈,再将当前元素入栈。
这样就保证了:栈中保留的都是比当前入栈元素小的值,并且从栈顶到栈底的元素值是单调递减的。
单调递减栈的入栈、出栈过程如下:
-
假设当前进栈元素为
x
,如果x
比栈顶元素大,则直接入栈。 -
否则从栈顶开始遍历栈中元素,把大于
x
或者等于x
的元素弹出栈,直到遇到一个小于x
的元素为止,然后再把x
压入栈中。
#include<iostream>
#include<stack>
using namespace std;
#define ll long long
const int N=3e6+5;
ll a[N],s1[N];
int main(){
stack<ll> s;
int n;
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=n;i>0;i--){
while(!s.empty()&&a[s.top()]>=a[i])
s.pop();
if(s.empty()) s1[i]=0; //第一个小a[i]的数
else s1[i]=s.top(); //因为我们是从后往前遍历的,所以如果等于的话也要弹出
s.push(i); //大于栈顶元素直接入栈
}
for(int i=1;i<=n;i++)
cout<<s1[i]<<" ";
cout<<endl;
}
如果插入时的栈为空,则说明右侧不存在比当前元素小的元素,就先存入栈中。如果后面有比当前元素小的,就把栈顶元素删除,把当前元素的下标入栈;如果比栈顶元素大就直接入栈,每次记录当前栈顶的值就为右侧第一个小于 a[i]的值的下标,如果该元素没有被弹出栈,则说明右侧不存在比当前元素小的元素。