线性数据结构--单调栈

单调栈

顾名思义,单调栈就是符合单调性的栈结构
既然符合单调性,所以自然而然就又分为单调递增栈单调递减栈

  • 单调递增栈:栈底到栈顶的元素从大到小
  • 单调递减栈:栈底到栈顶的元素从小到大

目的:用来解决类似 左边最近比当前元素小的元素 的问题

手动模拟单调栈

单调递增栈:现在有一组数10,3,7,4,11 从左到右依次入栈,则如果栈为空入栈元素值小于栈顶元素值,则入栈;否则需要把比入栈元素小的元素全部出栈

10入栈时,栈为空,直接入栈,栈内元素为10。

3入栈时,栈顶元素10比3大,则入栈,栈内元素为10,3。

7入栈时,栈顶元素3比7小,则栈顶元素出栈,此时栈顶元素为10,比7大,则7入栈,栈内元素为10,7。

4入栈时,栈顶元素7比4大,则入栈,栈内元素为10,7,4。

11入栈时,栈顶元素4比11小,4出栈,此时栈顶元素为7,仍比11小,栈顶元素7继续出栈,此时栈顶元素为10,仍比11小,10出栈,此时栈为空,11入栈,栈内元素为11

tip:其实单调栈的实现就是用STL的stack来模拟,是一种解决具体问题的思想,所以分析单调栈是建立在具体问题上的~~~

鸡汤来喽

找小的数字

题目描述

给定一个N,表示一个序列的长度,然后输入这个序列,输出序列每个元素的左边最近的比它小的数字,如果不存在则输出-1。

输入描述

输入包含两行 : 第一行一个N,表示序列长度 第二行输入N个数字,表示序列

输出描述

对应序列每个元素,均输出其左边最近的比它小的元素。

输入样例

5 3 4 2 7 5
输出样例

-1 3 -1 2 2
数据范围

1<=N<=105
​​序列中每个元素均不超过int最大值

冷静分析:找到左边最近的比它小的元素,意味着我们要维护一个单调递减栈(栈底到栈顶从小到大),然后就可以愉快的输出了~~~(一定要自己想着手写一遍!!!)

#include<iostream>
#include<algorithm>
#include<stack>
using namespace std;
const int N=1e5+10;
int n,a[N];
stack<int> q;
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i) scanf("%d",&a[i]);
	for(int i=1;i<=n;++i){
		while(!q.empty()&&q.top()>=a[i]) q.pop();
		if(q.empty()) printf("-1 ");
		else printf("%d ",q.top());
		q.push(a[i]);
	}
	return 0;
} 

是不是觉得很简单?别急,这只是智障模拟 ,现在上个难度:)

大鱼吃小鱼

题目描述

大鱼吃小鱼,小鱼吃虾米,虾米吃泥…
大自然中有其对应的生物链关系,生物与生物之间的相互关系就是从生产者→初级消费者→次级消费者→…的一种关系模式。

现在有N种生物,每个生物都有一个编号,表示其在生物链中的等级关系,编号越大表示它等级越高。如果当前位置上的生物等级高于其相邻的右侧生物等级,那么就可以将其直接吃掉,由于生物们反应都非常迅速,同一时刻某一个生物可能存在被吃掉和正在吃掉下一个的情况。

请你计算一下,这N个生物通过吃与被吃的关系直至任意相邻两个生物之间不再存在吃与被吃的关系。

输入描述

第一行一个N表示生物数量。

第二行输入N个整数, 表示每个生物的等级。

输出描述

输出最少需要多少时刻,最后所有相邻生物之间不再存在吃与被吃的关系。

输入样例1

10 10 9 7 8 6 5 3 4 2 1
输出样例1
2
输入样例2

6 1 2 3 4 5 6
输出样例2
0
数据范围 100%数据: 1≤n≤105 ​​所有生物等级为从1到n的整数。

老套路,冷静分析:(先读上好几遍谢谢) 第一反应这啥呀这是?动手模拟过样例后,似乎有点眉目

样例一解释: [10 9 7 8 6 5 3 4 2 1] →  [10 8 4] →  [10]
就是每一轮呈下降趋势的生物全进到第一个消费者肚子里,但我们不能每轮都维护一个单调栈,这样直接就TLE
所以在进一步分析,我们只要想办法维护一个单调栈的时候,把每个生物的第几次被吃的都求出来,然后答案就顺理成章成为这里面轮数的最大值?怎么求呢?
考虑一个生物,在前面没有比自己等级高的那肯定自己现在正等着吃别的生物而且永远不会被吃掉
但前面有比自己等级高的生物那自己早晚小命不保,所以自己被吃的轮数就是前面比自己小的生物里面最大轮数+1

#include<iostream>
#include<algorithm>
#include<stack>
using namespace std;
const int N=1e5+10;
int n,a[N],ans;
stack<pair<int,int> > q;
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i) scanf("%d",&a[i]);
	pair<int,int> now;
	for(int i=1;i<=n;++i){
		int sum=0;
		while(!q.empty()){
			now=q.top();
			if(now.first<a[i]){
				q.pop();
				sum=max(sum,now.second);
			}else break;
		}
		now.first=a[i];
		if(q.empty()) now.second=0;
		else now.second=sum+1;
		ans=max(ans,now.second);
		q.push(now);
	} 
	printf("%d\n",ans);
	return 0;
}

完结撒花~~~

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值