单调栈

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

posted @ 2025-04-26 16:50  cathyzro  阅读(38)  评论(0)    收藏  举报