单调栈
即栈内的元素是有某种单调性的。
用于求特定问题的解。
作用情景
[求一个数列的每个数的左边第一个比它小的数字](830. 单调栈 - AcWing题库)
要求左边第一个比它小的数,那么在之前每一个数入栈的时候就进行判断,只将满足递减单调性的数据存入,其余的弹出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| #include <iostream>
using namespace std;
const int N = 100010;
int stk[N], tt;
int main() { int n; scanf("%d", &n); for (int i = 0; i < n; i++) { int x; scanf("%d", &x); while (tt && stk[tt] >= x) tt--; if (tt) printf("%d ", stk[tt]); else printf("-1 "); stk[++tt] = x; } return 0; }
|
优先队列
与单调栈的定义类似,优先队列里的元素是按照某种单调性排列的。
使用优先队列可以简化特定要求的与队列有关的问题。
作用情景
[滑动窗口](154. 滑动窗口 - AcWing题库)
一组数据
给定一个大小为 k
的窗口,从数组的头开始滑动,窗口里最多只能同时存在k
个数。
求每次滑动时,窗口里的最大值和最小值。
与优先队列的处理方式类似,只将满足单调性的元素从队尾入队,不满足的 从队尾出队
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| #include <iostream>
using namespace std;
const int N = 1000010;
int n, k;
int a[N], q[N];
int main() { scanf("%d%d", &n, &k); for (int i = 0; i < n; i++) scanf("%d", &a[i]); int hh = 0, tt = -1; for (int i = 0; i < n; i++) { if (hh <= tt && q[tt] - k + 1 > q[hh]) hh++; while (hh <= tt && a[q[tt]] >= a[i]) tt--; q[++tt] = i; if (i >= k - 1) printf("%d ", a[q[hh]]); } printf("\n"); hh = 0, tt = -1; for (int i = 0; i < n; i++) { if (hh <= tt && i - k + 1 > q[hh]) hh++; while (hh <= tt && a[q[tt]] <= a[i]) tt--; q[++tt] = i; if (i >= k - 1) printf("%d ", a[q[hh]]); } return 0; }
|
总结
单调栈和优先队列的使用是为了满足特定集中情况下的算法需求,应用的场景比较有限
通常的使用场景是:
某个问题使用到了栈和队列的结构,但是朴素算法的遍历的复杂度太高,单调栈和优先队列可以优化栈和队列,使其具有一定的单调性,降低解决这些问题的复杂度。