单调栈

字面意思上理解,栈内元素是单调的,根据题目要求可能是单调递增或递减的


对于一个长度为 n 的序列,如果要求左边第一个比 x 小的数

暴力做法:

for(int i = 0; i < n; ++ i)
{
    for(int j = i - 1; j >= 0; --j)
    {
        if(a[j] < a[i])
        {
            ...;
            break;
        }
    }
}

但是我们可以有些数是永远不可能被当成答案输出的

例如,如果 6 的后面有 4 ,那么由于 4 比 6 小,且位于更右边,距离待求数更近,所以 6 不可能被当作答案输出。

如果我们把 x 之前的数都存入栈中,每新来一个 x ,就对其进行如下操作:

  • 如果栈顶元素比 x 大,那么栈顶元素由于更不接近后面待求的数,且和 x 相比更不可能做为答案输出,而被舍弃,pop 出栈
  • 如果栈顶元素比 x 小,那么栈顶元素就是左边第一个比 x 小的答案
  • 最后将 x 压入栈中

最后对于每一个询问的 x 栈中的数都是单调递增的


例如一个序列

3,2,4,6,5,9,9;栈:空

  1. 询问 3 左边第一个比自己小的数是:-1,因为没有比 3 小的数,此时栈空,3入栈,栈中有:3

  2. 询问 2 左边第一个比自己小的数是:-1,此时 2 比栈顶元素 3 大,3 出栈;因为没有比 2 小的数,此时栈空,2入栈,栈中有:2

  3. 询问 4 左边第一个比自己小的数是:2,因为栈顶元素 2 比 4 小,所以栈顶元素就是答案,4入栈,栈中有:2 4

  4. 询问 6 左边第一个比自己小的数是:4,因为栈顶元素 4 比 6 小,所以栈顶元素就是答案,6 入栈,栈中有:2 4 6

  5. 询问 5 左边第一个比自己小的数是:4,因为栈顶元素 6 比 5 大,所以 6 出栈,紧接着栈顶元素 4 比 5 小,停止出栈,栈顶元素就是答案,5入栈,栈中有:2 4 5

  6. 询问 9 左边第一个比自己小的数是:5,因为 5 比 9 小,栈顶元素就是答案,9 入栈,栈中元素:2 4 5 9

  7. 询问 9 左边第一个比自己小的数是:5,因为栈顶元素 9 大于等于 9 所以,栈顶元素 9 出栈,此时栈顶元素变为 5 比 9 小,所以栈顶元素就是答案,9 入栈,栈中元素:2 4 5 9

由于 B 比 A 小,E 比 D 小,且位于更右边,G 等于 F,当位于更右边,所以 A D F都将出栈,剩下蓝色那条单调递增的折线

例题

830. 单调栈 - AcWing题库

#include <iostream>
#include <string>
#include <cstdio>
#include <algorithm>
using namespace std;

const int N = 1e5 + 5;
int stk[N], tt;

int main()
{
    int n, x;
    scanf("%d", &n);
    for(int i = 0; i < n; ++ i)
    {
        scanf("%d", &x);
        while(tt && stk[tt] >= x) --tt;
        if(tt) printf("%d ", stk[tt]);
        else printf("-1 ");
        stk[++tt] = x;
    }
    return 0;
}
posted @ 2021-08-04 08:41  xiongyuqing  阅读(114)  评论(0编辑  收藏  举报