单调队列
1.算法分析
单调队列可以维护一个滑动窗口的最大值和最小值
2.模板
#include <bits/stdc++.h>
using namespace std;
int const N = 1e6 + 10;
int tt, hh, a[N], q[N];
int main() {
int n, k;
scanf("%d %d", &n, &k);
for (int i = 0; i < n; ++i) scanf("%d", &a[i]);
// 先输出窗口的最小值
hh = 0, tt = 0; // 窗口的头部元素和尾部元素
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]]);
}
cout << endl;
// 窗口的最大值
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;
}
3.典型例题
acwing154滑动窗口
题意: 给定一个大小为 n ≤ 1 0 6 n≤10^6 n≤106的数组。有一个大小为k的滑动窗口,它从数组的最左边移动到最右边。您只能在窗口中看到k个数字。每次滑动窗口向右移动一个位置。确定滑动窗口位于每个位置时,窗口中的最大值和最小值。
题解: 模板
代码:
#include <bits/stdc++.h>
using namespace std;
int const N = 1e6 + 10;
int tt, hh, a[N], q[N];
int main() {
int n, k;
scanf("%d %d", &n, &k);
for (int i = 0; i < n; ++i) scanf("%d", &a[i]);
// 先输出窗口的最小值
hh = 0, tt = 0; // 窗口的头部元素和尾部元素
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]]);
}
cout << endl;
// 窗口的最大值
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;
}