单调栈
字面意思上理解,栈内元素是单调的,根据题目要求可能是单调递增或递减的
对于一个长度为 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;栈:空
-
询问 3 左边第一个比自己小的数是:-1,因为没有比 3 小的数,此时栈空,3入栈,栈中有:3
-
询问 2 左边第一个比自己小的数是:-1,此时 2 比栈顶元素 3 大,3 出栈;因为没有比 2 小的数,此时栈空,2入栈,栈中有:2
-
询问 4 左边第一个比自己小的数是:2,因为栈顶元素 2 比 4 小,所以栈顶元素就是答案,4入栈,栈中有:2 4
-
询问 6 左边第一个比自己小的数是:4,因为栈顶元素 4 比 6 小,所以栈顶元素就是答案,6 入栈,栈中有:2 4 6
-
询问 5 左边第一个比自己小的数是:4,因为栈顶元素 6 比 5 大,所以 6 出栈,紧接着栈顶元素 4 比 5 小,停止出栈,栈顶元素就是答案,5入栈,栈中有:2 4 5
-
询问 9 左边第一个比自己小的数是:5,因为 5 比 9 小,栈顶元素就是答案,9 入栈,栈中元素:2 4 5 9
-
询问 9 左边第一个比自己小的数是:5,因为栈顶元素 9 大于等于 9 所以,栈顶元素 9 出栈,此时栈顶元素变为 5 比 9 小,所以栈顶元素就是答案,9 入栈,栈中元素:2 4 5 9
由于 B 比 A 小,E 比 D 小,且位于更右边,G 等于 F,当位于更右边,所以 A D F都将出栈,剩下蓝色那条单调递增的折线
例题
#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;
}
本文来自博客园,作者:xiongyuqing,转载请注明原文链接:https://www.cnblogs.com/xiongyuqing/p/15097271.html