单调栈的思想及应用

本文首发于我的个人网站

单调栈的思想及应用

image-20230126103038023

思想及实现

定义

单调栈,顾名思义就是单调的栈,栈内的元素是单调递增的或者单调递减的。

举例

以一个单调递增的栈为例,给定一个数组 7 , 3 , 9 , 1 , 2 , 8 , 4 , 9 7,3,9,1,2,8,4,9 7,3,9,1,2,8,4,9,将其中的元素依次放入栈中

得到一个形如 1 , 2 , 4 , 9 1,2,4,9 1,2,4,9的栈

由于 1 1 1以前的数都更小,就得在插入 1 1 1前全部弹出

如何维护

以单调递减(严格)的单调栈为例,要想维护栈的单调性,只需要在入栈、出栈的时候,保证入栈元素小于栈顶元素。

所以,假设我们当前要入栈的数为x

  • 如果栈顶元素比x大,那么我们直接入栈即可
  • 否则,栈顶元素小于等于x时,我们可以通过不断弹出栈顶元素的方式来保证入栈前栈顶元素大于x

那么,入栈的代码就能写出来了

int stk[N], tt = -1;
void push(int x) {
    while (tt >= 0 && x >= stk[tt]) tt --;
    stk[++tt] = x;
}

出栈的代码和普通的栈一样,不用变

int stk[N], tt = -1;
void pop(int x) {
	if (tt >= 0) tt --;
}

与单调栈的区别

如果没有左边界,考虑单调栈,如果有左边界,考虑单调队列。

模板题

P5788 【模板】单调栈 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

由于题目中要求的是数组下标,所以栈内维护下标,利用索引的方式比较栈顶和待插入元素大小

参考代码

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 3e6 + 10;

int n;
int a[N];
int stk[N], tt;
int ans[N];

int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);

	for (int i = n; i >= 1; i -- ) {
        // 当栈内有元素时,如果无法保证单调,则弹出栈顶
		while (tt && a[stk[tt]] <= a[i]) tt --;
		ans[i] = stk[tt]; // 更新答案
        // 入栈
		stk[++ tt] = i;
	}
	for (int i = 1; i <= n; i ++ )
		printf("%d ", ans[i]);

	return 0;
}

单调栈的应用

主要应用场景:求下一个大于/小于自身的数

P2422 良好的感觉 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

P1901 发射站 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

历年真题

找规律题,发现性质之后,单调栈很容易就能写出来:Problem - M - Codeforces

https://nanti.jisuanke.com/t/42391

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值