单调栈应用

一.模板题

给定一个长度为 N的整数数列,输出每个数左边第一个比它小的数,如果不存在则输出 −1。

输入格式

第一行包含整数 N,表示数列长度。

第二行包含 N 个整数,表示整数数列。

输出格式

共一行,包含 N 个整数,其中第 i个数表示第 i 个数的左边第一个比它小的数,如果不存在则输出 −1。

数据范围

1≤N≤10^5
1≤数列中元素≤10^9

输入样例:
5
3 4 2 7 5
输出样例:
-1 3 -1 2 2

分析:

 原理:用单调递减栈,当该元素可以入栈的时候,栈顶元素就是它左侧第一个比它小的元素。

//单调递增栈:栈顶到栈底单调递增

//单调递减栈:栈顶到栈底单调递减

对于待处理的元素,分为三种情况讨论

1.栈顶元素>=待处理元素,则依次将栈顶元素弹出栈,直到栈顶元素小于待处理元素或者栈中无元素为止。

2.栈为空,则直接将待处理元素压入栈

3.栈顶元素<待处理元素,则将待处理元素压入栈,此时栈顶元素即待处理元素左侧第一个比它小的数

来康康例子:

对于3 4 2 7 5:

步骤待处理的元素操作栈(左侧为栈底)

该元素左侧第一个

比它小的数

13栈为空,3入栈[3]-1
243<4,4入栈[3,4]3
324>2 ,3>2,4和3依次出栈,2入栈[2]-1
472<7,7入栈[2,7]2
557>5,7出栈;2<5,5入栈[2,5]2

代码实现:

#include<bits/stdc++.h>
using namespace std;

stack<int> t;

int main(){
	int n,x;
	cin>>n;
	while(n--){
		cin>>x;
		//若栈顶元素>=待处理元素,则栈顶元素出栈 
		while(t.size()&&t.top()>=x)t.pop(); 
		
		//若栈为空
		if(t.size()==0)cout<<"-1 ";
		
		//若栈顶元素<待处理元素,则栈顶元素就是所求值 
		else cout<<t.top()<<' ';
		
		 
		t.push(x);
	}
	return 0;
}

或用数组模拟栈

#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int stk[N];
int t=-1;

int main(){
	int n;
	cin>>n;
	while(n--){
		int x;
		cin>>x;
		while(t>=0&&stk[t]>=x)t--;
		
		if(t==-1)cout<<"-1 ";
		else cout<<stk[t]<<' ';
		
		stk[++t]=x;
	}
	return 0;
}

二.接雨水

给定 n个非负整数表示每个宽度为 11 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

例如,当给定数字序列为 0,1,0,2,1,0,1,3,2,1,2,1 时,柱子高度图如下所示,最多可以接 6 个单位的雨水。

输入格式

第一行包含整数 n。

第二行包含 n个非负整数。

输出格式

输出一个整数,表示最大接水量。

数据范围

1≤n≤10^5,
序列中元素均不大于 1000。

输入样例:
12
0 1 0 2 1 0 1 3 2 1 2 1
输出样例:
6

 

分析:

采用单调递增栈(栈顶到栈底单调递增)

设置last,用于标记已计算雨水层数

例如:4 2 1 0 3

  1. 由于栈为空,所以当前元素的下标直接入栈,栈为  [0],对应值为 [4]
  2. 由于当前元素2小于栈顶元素h[0],所以当前元素的下标入栈,栈为[0,1],对应值为 [4,2]
  3. 由于当前元素1小于栈顶元素h[1],所以当前元素的下标入栈,栈为[0,1,2],对应值为 [4,2,1]
  4. 由于当前元素0小于栈顶元素h[2],所以当前元素的下标入栈,栈为[0,1,2,3],对应值为 [4,2,1,0]
  5. 由于当前元素3大于栈顶元素h[3],计算储水量res+=(h[3]-last)*(4-3-1),res=0,更新last=h[3];而后弹出栈顶元素,栈为[0,1,2],对应值为[4,2,1]
  6. 由于当前元素3大于栈顶元素h[2],计算储水量res+=(h[2]-last)*(4-2-1),res=1,更新last=h[2];而后弹出栈顶元素,栈为[0,1],对应值为[4,2]
  7. 由于当前元素3大于栈顶元素h[1],计算储水量res+=(h[1]-last)*(4-1-1),res=3,更新last=h[1];而后弹出栈顶元素,栈为[0],对应值为[4]
  8. 由于当前元素3小于栈顶元素h[0],且当前元素下标与栈顶元素下标不相邻,所以形成凹槽,计算储水量res+=(h[i]-last)*(4-0-1),res=6

注:

  • 每遍历一个下标,都必须更新last为0
  • 使用单调栈,即可找到每个元素左边第一个比它大的值,若该值的下标与其不相邻,说明两个元素之间能够形成凹槽,即能够储存水
  • 当前储水量=(两柱子之间的距离)*(栈顶柱子高度-已计算的雨水层高)
  • 两柱子之间的距离 l=i-t.top()-1
  • 栈顶柱子高度-已计算的雨水层高=h[t.top()]-last

代码如下:

#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int n;
int h[N];
stack<int> t;
int main(){
	cin>>n;
	for(int i=0;i<n;i++)cin>>h[i];  //柱子的高度为h[i]
	
	int res=0;            //能接到的雨水总数
	for(int i=0;i<n;i++){
		int last=0;       //储存上一个高度
		
		//判断栈不为空且栈顶元素小于等于当前元素时 
		while(t.size()!=0&&h[t.top()]<h[i]){
			
			//每次删除一个柱子时,先计算当前柱子与即将删除的柱子间(栈顶元素)的储水量 
			res+=(h[t.top()]-last)*(i-t.top()-1);
			last=h[t.top()];
			t.pop();
		}
		if(t.size()!=0&&i-t.top()>1)res+=(h[i]-last)*(i-t.top()-1);
		
		//当前柱子的下标入栈 
		t.push(i);
	} 
	cout<<res;
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值