单调栈
PART 1 : 单调栈
目的:
用一个栈维护一个序列,使栈中的元素具有单调性,方便调用某个元素及其之后第一个大于或者小于它的值
实现思路:
先说一下总体思路:
使用数组和指针(当然只是一个int存储的下标)模拟栈。指针指向栈顶。
接下来我们以求当前元素之前的最大值来举栗子),
因为要求出当前值之后的第一个大于它的值,那么可以使栈中元素单调,当遇到一个比该元素大的元素,弹出它,记录这个把它弹出的元素的下标,就可以得出第一个比他大的元素的下标了。
在实现的过程中可以发现,我们遍历到某个元素并试图用该元素单调其它元素时,求的是其它元素之后的第一个大于它的元素。
以上是单调栈的总体思路,那么现在来详细说一下具体过程:
遍历过程中对于每一个元素,判断它的值是否大于栈顶。因为栈中元素单调递减,如果不大于栈顶,就更不可能大于栈顶下面的其它元素。如果大于栈顶,那么弹出栈顶,将栈顶的“该元素之后的第一个大于它的元素”设置为当前所遍历的元素,然后继续遍历下一个栈顶,重复上述步骤。
接下来我们用一个恙栗,来模拟一下存储过程:
1 4 9 5 8 0 10
- step1:1入栈 栈中没有元素,直接入栈。top指向1(这里指的是元素1在原数组里的位置) 栈中元素:[1(top)
- step2:4入栈 栈顶是1,<4,将1弹出,将第一个大于1的数的位置设置为2(4在原数组里的位置) 栈中元素:[4(top)
- step3:9入栈 栈顶是4,<9,将4弹出,将第一个大于4的数的位置设置为3(9在原数组里的位置),top指向3 栈中元素:[9(top)
- step4:5入栈 栈顶是9,>5,将5入栈,top指向4(5在原数组里的位置) 栈中元素:[9,5(top)
- step5:8入栈 栈顶是5,<8,将5弹出,将第一个大于5的数的位置设置为5(8在原数组里的位置),top指向5 栈中元素:[9,8(top)
- step6:0入栈 栈顶是8,>0,将0入栈,top指向6 栈中元素:[9,8,0(top)
- step7:10入栈 栈顶是0,<10,将0弹出,将第一个大于0的数的位置设置为7,栈顶指向7,继续判断
新栈顶为8,<10 将8弹出,将第一个大于8的数设置为7,栈顶指向7,继续判断
新栈顶为9,<10 将9弹出,将第一个大于9的数设置为7,栈顶指向7,栈中已经没有7号之外的元素,算法结束。 栈中元素:[10(top)
经过模拟我们发现,每一个元素只能入栈一次,出栈一次,所以时间复杂度控制在O(n)
代码实现:
点击查看代码
#include<bits/stdc++.h>
using namespace std;
inline int read(){//快读,不用理他
int wow=0,f=1;
char c=getchar();
while(c>'9' || c<'0'){
if(c=='-'){
f=-f;
}
c=getchar();
}
while(c>='0' && c<='9'){
wow=(wow<<3)+(wow<<1)+c-'0';
c=getchar();
}
return wow*f;
}
const int N=3e6+5;
int n,a[N],ans[N],q[N];
int main(){
cin>>n;
for(int i=1;i<=n;i++) a[i]=read();
int top=0;
for(int i=1;i<=n;i++){
while(top>0 && a[q[top]]<a[i]){//当栈不为空且当前值大于栈顶
ans[q[top]]=i;//设置“第一个比qtop大的位置”
top--;//出栈
}
q[++top]=i;
}
for(int i=1;i<=n;i++) cout<<ans[i]<<" ";
}
题目:洛谷P5788