首页 > 其他分享 >单调栈

单调栈

时间:2023-02-22 12:13:37浏览次数:23  
标签:10 const int tt include 单调

单调栈

给定一个长度为 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

思路

题目需要求每个数左边第一个比它小的数

如果直接暴力的话,时间复杂度是\(o(n^2)\)显然tle
那么我们可以考虑用空间换时间,将之前扫描过的数存储起来

然后我们需要思考的是之前扫描过的什么数对答案是没有贡献的?
设\(a_{i-2},a_{i-1},a_i\)为连续的三个数,\(a_i\)为当前枚举到的数
显然,如果\(a_{i-2} \ge a_{i-1}\),那么它对答案是没有贡献的(因为如果\(a_{i-1} < a_i\),那么\(a_{i-1}\)就是答案,如果\(a_{i-1} \ge a_i\),那么\(a_{i-2} \ge a_{i-1}\ge a_i\),\(a_{i-2}\)更不可能是答案)

因此,我们只需要维护一个单调递增的栈,每次输出栈顶元素即可

什么是单调栈

栈内元素有单调性,通过维护单调栈实现\(o(n)\)优化

如何维护一个单调栈

单调递增栈:在保持栈内元素单调递增的前提下(如果栈顶元素大于要入栈的元素,将将其弹出),将新元素入栈。
image

单调递减栈:在保持栈内元素单调递减的前提下(如果栈顶元素小于要入栈的元素,则将其弹出),将新元素入栈。
image
(图片来源:Thr96)

什么时候使用单调栈

给定一个序列,求序列中的每一个数左边或右边第一个比他大或比他小的数在什么地方;

动图演示

以 3 4 2 7 5 为例,过程如下:
/i/ll/?i=20201211221031165.gif#pic_center
(动图来源:Hasity)

代码1(stl栈)

点击查看代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
using namespace std;

#define X first
#define Y second

typedef pair<int,int> pii;
typedef long long LL;
const char nl = '\n';
const int N = 1e6+10;
const int M = 2e5+10;
int n,m;
int a[N];
stack<int> s;

void solve(){
	cin >> n;
	for (int i = 1; i <= n; ++i){
		cin >> a[i];		//只用到当前元素
		while(s.size() && a[i] <= a[s.top()])s.pop(); 		//弹出栈内所有大于等于当前元素的数,从而维护单调递增序列
		if(s.size())cout << a[s.top()] << " ";		//如果栈不空则输出答案
		else cout << -1 << " ";			//栈空说明答案不存在
		s.push(i);		//当前元素下标入栈
	}
	//为什么单调栈储存下标?
	//因为如果使用下标储存可以通过下标访问数组,如果使用值储存的话不能通过值访问下标(本题用值储存问题也不大,只是为了方便习惯储存下标)
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);

	solve();
}

代码2(数组模拟栈)

点击查看代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
using namespace std;

#define X first
#define Y second

typedef pair<int,int> pii;
typedef long long LL;
const char nl = '\n';
const int N = 1e6+10;
const int M = 2e5+10;
int n,m;
int a[N],st[N],tt;

void solve(){
	cin >> n;
	for (int i = 1; i <= n; ++i){
		cin >> a[i];
		while(tt && a[st[tt]] >= a[i])tt --;
		if(tt)cout << a[st[tt]] << " ";
		else cout << -1 << " ";
		st[++ tt] = i;
	}
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);

	solve();
}

一些问题

1. 为什么单调栈储存下标?

因为如果使用下标储存可以通过下标访问数组,如果使用值储存的话不能通过值访问下标(本题用值储存问题也不大,只是为了方便习惯储存下标)

2. 为什么有STL不用,反而要自己用数组来模拟stack?

  1. 最致命的原因,99%的测评网站,竞赛系统不会对C++代码使用O2优化,导致使用STL的速度慢,容易造成TLE(超时)。
  2. 学习栈的操作流程和内部原理。

拓展

  1. 每个数左边第一个比它大的数
点击查看代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
using namespace std;

#define X first
#define Y second

typedef pair<int,int> pii;
typedef long long LL;
const char nl = '\n';
const int N = 1e6+10;
const int M = 2e5+10;
int n,m;
int a[N],st[N],tt;

void solve(){
	cin >> n;
	for (int i = 1; i <= n; ++i){
		cin >> a[i];
		while(tt && a[st[tt]] <= a[i])tt --;
		if(tt)cout << a[st[tt]] << " ";
		else cout << -1 << " ";
		st[++ tt] = i;
	}
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);

	solve();
}

  1. 每个数右边第一个比它小的数
点击查看代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
using namespace std;

#define X first
#define Y second

typedef pair<int,int> pii;
typedef long long LL;
const char nl = '\n';
const int N = 1e6+10;
const int M = 2e5+10;
int n,m;
int a[N],st[N],tt;
vector<int> ans;

void solve(){
	cin >> n;
	for(int i = 1; i <= n; i ++ )cin >> a[i];
	for (int i = n; i >= 1; i -- ){
		while(tt && a[st[tt]] >= a[i])tt --;
		if(tt)ans.push_back(a[st[tt]]);//cout << a[st[tt]] << " ";
		else ans.push_back(-1);//cout << -1 << " ";
		st[++ tt] = i;
	}
	for (int i = ans.size() - 1; i >= 0; i -- )cout << ans[i] << " ";
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);

	solve();
}

3.每个数右边第一个比它大的数

点击查看代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
using namespace std;

#define X first
#define Y second

typedef pair<int,int> pii;
typedef long long LL;
const char nl = '\n';
const int N = 1e6+10;
const int M = 2e5+10;
int n,m;
int a[N],st[N],tt;
vector<int> ans;

void solve(){
	cin >> n;
	for(int i = 1; i <= n; i ++ )cin >> a[i];
	for (int i = n; i >= 1; i -- ){
		while(tt && a[st[tt]] <= a[i])tt --;
		if(tt)ans.push_back(a[st[tt]]);//cout << a[st[tt]] << " ";
		else ans.push_back(-1);//cout << -1 << " ";
		st[++ tt] = i;
	}
	for (int i = ans.size() - 1; i >= 0; i -- )cout << ans[i] << " ";
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);

	solve();
}

标签:10,const,int,tt,include,单调
From: https://www.cnblogs.com/J-12045/p/17143904.html

相关文章

  • 浅谈单调队列解决滑动窗口问题
    这次我们了解一下滑动窗口的问题首先,让我们了解一下滑动窗口是什么?这里有一张图(来自POJ),解释了滑动窗口的意思:我们可以看见,一个长度固定为3的框(窗口)从左端点移动到右......
  • 单调栈
    栈是一种后进先出的线性的数据结构,但若在栈的结构之上再规定栈中元素大小需满足单调关系,即成为单调栈。单调栈分为单调递增栈和单调递减栈:1.单调递增栈即栈内元素保持单......
  • 单调队列
    单调队列是什么呢?可以直接从问题开始来展开。Poj2823给定一个数列,从左至右输出每个长度为m的数列段内的最小数和最大数。数列长度:N<=106,m<=N暴力解很直观的一种解法,那就......
  • 代码随想录——单调栈
    每日温度题目中等什么时候用单调栈呢?通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,此时我们就要想到可以用单调栈了。classSoluti......
  • LeetCode接雨水(/dp 单调栈 双指针)
    原题解题目给定n个非负整数表示每个宽度为1的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。约束题解解法一classSolution{public:inttra......
  • 决策单调性与四边形不等式
    参考自:《决策单调性与四边形不等式》,彭思进,感谢Itst的耐心答疑/bx《决策单调性与四边形不等式-学习笔记》,p_b_p_b的博客一、决策单调性与四边形不等式定义1.......
  • 单调
    超级神仙题。题意给你一个序列\(a_1\dotsa_n\),值域为\([1,3]\)最大化选择的不交的合法子序列数,一个合法的子序列是\(1,2,3\)或\(3,2,1\),\(n\leq10^5\),输出方案......
  • 【CSP201312-3】最大的矩形,单调栈
    problem201312-3试题名称:最大的矩形时间限制:1.0s内存限制:256.0MB问题描述:问题描述在横轴上放了n个相邻的矩形,每个矩形的宽度是1,而第i(1≤i≤n)个矩形的高度......
  • 1.4 单调栈
    84.柱状图中最大的矩形最大矩形的高度瓶颈可能在于各个柱子的高度,如图所示基于以上观察,一个朴素算法是:枚举每种可能的高度瓶颈1.1向左、右扩展宽度1.2擂台更新......
  • 【tyvj1305】最大子序和(单调队列)
    problem给你一个长为n的序列求一个长不超过m的连续子段,使子段和最大solution如果n<=10^3,我们很容易写出枚举(s是前缀和,区间[l,r]的和就是s[r]-s[l-1]。枚举l,r即可。for(int......