“如果一个选手比你小还比你强,你就可以退役了。”——单调队列的原理
单调队列主要的解决问题:单调队列是一种主要用于解决滑动窗口类问题的数据结构,即,在长度为 n 的序列中,求每个长度为 m 的区间的区间最值。它的时间复杂度是 O(n);
由于是维护区间所以需要两边都需要能够吐出数字,所以需要用双向队列进行维护
例题
给定一个长度为n的数组a。
有一个大小为k的滑动窗口(窗口中只能看到k个元素),它从数组的最左边,每次向右移动一个位置,直到移动到最右边。
你需要回答出滑动窗口在每个位置时,窗口中的最大值和最小值。
输入
第一行:两个整数n,k。(51≤k≤n≤2×10^5)
第二行:n个整数,代表数组a。(−10^6≤ai≤10^6,1≤i≤n)
输出
第一行:从左到右,滑动窗口在每个位置的最大值。
第二行:从左到右,滑动窗口在每个位置的最小值。
样例输出
样例输出
1 2
| 3 3 1 2 2 8 0 0 -5 -5 -5 1
|
ANSWER
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 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
constexpr int N = 2e5 + 10;
int a[N];
void solve() {
int n, k;
cin >> n >> k;
for (int i = 1; i <= n; i++) cin >> a[i];
deque<int> dq;
for (int i = 1; i <= n; i++) {
while (dq.size() && dq.front() <= i - k) dq.pop_front();
while (dq.size() && a[dq.back()] <= a[i]) dq.pop_back();
dq.push_back(i);
if (i >= k) cout << a[dq.front()] << ' '; }
cout << '\n';
dq = deque<int>();
for (int i = 1; i <= n; i++) {
while (dq.size() && dq.front() <= i - k) dq.pop_front();
while (dq.size() && a[dq.back()] >= a[i]) dq.pop_back();
dq.push_back(i);
if (i >= k) cout << a[dq.front()] << ' ';
}
cout << '\n';
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t = 1;
while (t--) {
solve();
}
}
|
数组实现
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 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
constexpr int N = 2e5 + 10;
int a[N],dq[N];
void solve() {
int n, k;
cin >> n >> k;
int hh =1,tt = 0 ;
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= n; i++) {
while (hh<=tt && dq[hh] <= i - k) hh++;
while (hh<=tt && a[dq[tt]]<= a[i]) tt--;
dq[++ tt] = i;
if (i >= k) cout << a[dq[hh]] << ' ';
}
cout << '\n';
hh =1,tt = 0;
for (int i = 1; i <= n; i++) {
while (hh<=tt && dq[hh]<=i-k) hh++;
while (hh<=tt && a[dq[tt]] >= a[i]) tt--;
dq[++ tt] = i;
if (i >= k) cout << a[dq[hh]] << ' ';
}
cout << '\n';
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t = 1;
while (t--) {
solve();
}
}
|