【知识点笔记】 单调栈

1. 传送门

学习传送门:单调栈 b站 up麦克老师讲算法

2. 笔记内容

2.1 应 用

      求解下一个大于x元素或是小于x元素的位置

2.2 示 例

      给定一个数组a,计算后获得一个大小相同的数组res,res数组的第i个值对应a数组第i个位置的元素,res[i]的值表示a[i]之后的第几个元素比a[i]大(如果之后没有比a[i]大的元素,或者当前元素已经是最后一个元素,则在res数组的对应位置放上-1)

下标0123456
a数组1345296
res数组11121-1-1
res2数组34599-1-1

表中a数组为原数组元素,res数组用来存储下一个大于目前所指元素的元素下标与当前下标的距离(如果不存在满足条件的元素则该位用-1填充),res2数组用来存储下一个大于目前所指元素的元素值(不存在满足条件的元素也用-1填充)。

2.2.1 使 用 方 式

代码思想:从后向前遍历a数组,最后一个元素直接入栈res2填-1,从倒数第二个元素开始判断栈顶元素是否小于等于遍历到的元素,若栈顶元素小于等于遍历到的元素,则将栈顶元素出栈,循环判断栈中元素,直到栈为空或者栈中元素大于当前元素,判断当前栈是否为空,如果栈为空则将-1填入当前元素对应的res2数组位置中,如果栈非空则将栈顶元素填入res2。

void nextGreater(int a[], int n) {
	stack<int> s;
	for(int i = n - 1; i >= 0; --i) {
		while(s.size() && s.top() <= a[i]) {
			//当栈非空并且栈顶元素小于等于当前遍历到的元素将栈顶元素出栈
			s.pop();
		}
		res2[i] = s.empty() ? -1 : s.top();
		//当单调栈为空(在该元素之后没有比它大的元素)res数组中填入-1
		//当单调栈非空(栈顶元素为比该元素大的后一个元素)res数组中填入栈顶元素
		s.push(a[i]);
		//将当前元素入栈
	}
}
Tip:
通过while循环保证栈中元素都大于当前元素。
2.2.2 整 体 代 码 实 现
#include <iostream>
#include <stack>

using namespace std;

struct node {
	int index;
	int data;
};

int res[10];

void nextGreater(int a[], int n) {
	stack<node> s;
	for (int i = n - 1; i >= 0; --i) {
		while (s.size() && s.top().data <= a[i]) {
			s.pop();
		}
		res[i] = s.empty() ? -1 : s.top().index - i;
		node temp;
		temp.index = i;
		temp.data = a[i];
		s.push(temp);
	}
}

int main() {
	int num[7] = {1, 3, 4, 5, 2, 9, 6};
	nextGreater(num, 7);
	for (int i = 0; i < 7; ++i) {
		if (i != 0)
			printf(" ");
		printf("%d", res[i]);
	}
	return 0;
}

3. 试一试

洛谷 P5788 【模板】单调栈

代码

#include <iostream>
#include <stack>

using namespace std;

struct node {
	int index;
	int data;
};

int res[3000001];
int num[3000001];

void nextGreater(int n) {
	stack<node> s;
	for(int i = n; i >= 1; --i) {
		while(s.size() && s.top().data <= num[i]) {
			s.pop();
		}
		res[i] = s.empty() ? 0 : s.top().index;
		node temp;
		temp.index = i;
		temp.data = num[i];
		s.push(temp);
	}
}

int main() {
	int n;
	scanf("%d", &n);
	for(int i = 1; i <= n; ++i) {
		scanf("%d", &num[i]);
	}
	nextGreater(n);
	for(int i = 1; i <= n; ++i) {
		if(i != 1) printf(" ");
		printf("%d", res[i]);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值