C++ 单调队列
单调队列:先进先出,是一个双端队列,队首只能删除元素,队尾可以进行插入和删除
单调队列代码框架
#include<iostream>
#include<deque>
using namespace std;/* 单调队列模版 */
#define maxn 100001template<typename T>
bool max(T a, T b) {return a <= b;
}template<typename T>
bool min(T a, T b) {return a >= b;
}
//给定一个长度为n的序列
//并且一个区间长度k
//求出所有长度不超过k的连续区间中的最大值(最小值)
template<typename T>
void findIntervalMinMax(int n, T h[], int k, T ans[], bool (*cmp)(T a, T b)) {// ans[i]代表的是以i为结尾的,且最大长度为k的区间里面的最大值(最小值)deque<int> q;for (int i = 0; i < n; ++i) {while (!q.empty() && cmp(h[q.back()], h[i])) {q.pop_back();}q.push_back(i);while (q.back() - q.front() + 1 > k) {q.pop_front();}// ans[i]代表以i结尾, 且长度不超过k的区间中,元素的最大值(最小值)ans[i] = h[q.front()];}}
/* 单调队列模版 */int main() {int h[] = { 8, 7, 6, 9, 11 };int ans[10];findIntervalMinMax(5, h, 3, ans, max);for (int i = 0; i < 5; ++i) {cout << ans[i] << " ";}cout << endl;findIntervalMinMax(5, h, 3, ans, min);for (int i = 0; i < 5; ++i) {cout << ans[i] << " ";}cout << endl;
}代码练习1 对应洛谷 滑动窗口 代码见下
#include<iostream>
#include<deque>
using namespace std;/* 单调队列模版 */
#define maxn 1000001template<typename T>
bool max(T a, T b) {return a <= b;
}template<typename T>
bool min(T a, T b) {return a >= b;
}
//给定一个长度为n的序列
//并且一个区间长度k
//求出所有长度不超过k的连续区间中的最大值(最小值)
template<typename T>
void findIntervalMinMax(int n, T h[], int k, T ans[], bool (*cmp)(T a, T b)) {// ans[i]代表的是以i为结尾的,且最大长度为k的区间里面的最大值(最小值)deque<int> q;for (int i = 0; i < n; ++i) {while (!q.empty() && cmp(h[q.back()], h[i])) {q.pop_back();}q.push_back(i);while (q.back() - q.front() + 1 > k) {q.pop_front();}// ans[i]代表以i结尾, 且长度不超过k的区间中,元素的最大值(最小值)ans[i] = h[q.front()];}}
/* 单调队列模版 */int h[maxn], ans[maxn];int main() {int n, k;cin >> n >> k;for (int i = 0; i < n; ++i) {cin >> h[i];}findIntervalMinMax(n, h, k, ans, min);for (int i = k - 1; i < n; ++i) {cout << ans[i] << " ";}cout << endl;findIntervalMinMax(n, h, k, ans, max);for (int i = k - 1; i < n; ++i) {cout << ans[i] << " ";}cout << endl;return 0;
}代码练习2 对应蓝桥云课 MAX最值差 代码见下
#include<iostream>
#include<deque>
using namespace std;/* 单调队列模版 */
#define maxn 1000001template<typename T>
bool max(T a, T b) {return a <= b;
}template<typename T>
bool min(T a, T b) {return a >= b;
}
//给定一个长度为n的序列
//并且一个区间长度k
//求出所有长度不超过k的连续区间中的最大值(最小值)
template<typename T>
void findIntervalMinMax(int n, T h[], int k, T ans[], bool (*cmp)(T a, T b)) {// ans[i]代表的是以i为结尾的,且最大长度为k的区间里面的最大值(最小值)deque<int> q;for (int i = 0; i < n; ++i) {while (!q.empty() && cmp(h[q.back()], h[i])) {q.pop_back();}q.push_back(i);while (q.back() - q.front() + 1 > k) {q.pop_front();}// ans[i]代表以i结尾, 且长度不超过k的区间中,元素的最大值(最小值)ans[i] = h[q.front()];}}
/* 单调队列模版 */int h[maxn], G[maxn], F[maxn];int main() {int n, k;cin >> n >> k;for (int i = 0; i < n; ++i) {cin >> h[i];}findIntervalMinMax(n, h, k, G, max);findIntervalMinMax(n, h, k, F, min);int ret = -1000000000;for (int i = 0; i < n; ++i) {int v = G[i] - F[i];if (v > ret) {ret = v;}}cout << ret << endl;return 0;
}