单调栈

题目 单调栈

image-1bcadaf0

思路分析

用的地方很少 其实可以归纳进双指针问题 是对双指针问题暴力后的一个改进

比如 在序列中 要求每个数左边的最近的比它小的数

3 4 2 7 9

-1 3 -1 2 7

乍一看是双指针问题 暴力过一遍

i从0~n

j从i-1~0

找小于a[i]的数

break

接下来就是找特点 寻求优化

i往右走的过程中 可以使用栈去存放左边的所有元素

那这就有优化空间了

怎么减少栈里面没用的数据 从而减少出栈的次数

分析一下

3 4 2 7

如果在7这个位置 前面的3 4 2应该都是满足小于7的

但是取到的只有2 因为最近

那意思就是说 在7这里 栈里面完全可以只有2

3 4 2 7 9

9这里 可不可以栈中只有7?

3 4 2 7 4

显然不能 如果换成一个小于7的数 真正的结果2就丢失了

可以发现 若存在 x=ay的情况

则可以把ax剔除掉

ay永远是较与ax的最优解 ax存不存在就没关系了(ay在一天 ax就永无出头之日)

画成图就是说 栈中只要存在这种往下的线段 就去掉

最后得到的栈里面的元素一定是单调的

且栈顶一定就是要求的值 要么就是空 没有符合要求的值

其实就是一个变插入边判断删除的过程 确保栈内都是答案

这样每个元素都最多只会进栈出栈一次 相较于原本的每次都前面所有数入栈再逐个出栈找

要优化了很多

然后原本的数组都可以不用另外存储了 反正下一个数的答案要么就是栈顶要么就是栈空没有 直接依次对各个数进行判断 对单调栈进行调整

//栈里有元素 且当前元素进入后会产生逆序 就删掉那些没有出头日的元素

while(tt && stk[tt]>=x)

tt--;

if(!tt)

printf(“-1 “);//栈空的话 说明没有答案

else

printf(“%d “,stk[tt]);//否则栈顶元素就是答案

stk[++tt]=x;//把该元素入栈

image-150c5552 image-56889add

代码实现

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

const int N=100010;
int stk[N];
int tt;

int main()
{
    int n;
    cin>>n;
    while(n--)
    {
        int x;
        scanf("%d",&x);
        //插入的同时就对栈去进行处理
        while(tt && stk[tt]>=x)//如果出现逆序 就出栈
            tt--;
        if(!tt)//如果栈空了 说明不存在符合要求的数据
            printf("-1 ");
        else//如果栈里还有元素 那么栈顶的肯定就是符合条件的
            printf("%d ",stk[tt]);
        stk[++tt]=x;//把当前元素入栈
    }
    return 0;
}

同类题型

视频讲解


⬅️ 队列 🏠 00-听课板子 ➡️ 单调队列