题解
滑动窗口的最大最小值问题,典型的单调队列应用。
所谓单调队列,顾名思义,队列是单调的,即队列里的元素严格的递增或递减,这意味着队首元素总是最小值或最大值,这是一个很有用的性质。
单调队列支持两种操作,队首删除,队尾插入或删除。
以求最小值为例,需要维护一个单调递增队列,每次有新元素要入队的时候,删除队尾元素直到队尾元素小于该新元素或队列空。
在此题背景下,窗口每滑一格,意味着要删除滑动前窗口的最左边元素,如果该元素是队首元素,则进行队首删除操作(即队列的大小比窗口更大),然后新元素入队。
#include <iostream>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn = 1000000 + 10;
int a[maxn];
int n, k;
// TLE
void solve()
{
set<int> ValQue;
vector<int> maxAns, minAns;
for(int i = 0; i < k; ++i){
ValQue.insert(a[i]);
}
minAns.push_back(*ValQue.begin());
maxAns.push_back(*ValQue.rbegin());
for(int i = k; i < n; ++i){
ValQue.erase(a[i - k]);
ValQue.insert(a[i]);
minAns.push_back(*ValQue.begin());
maxAns.push_back(*ValQue.rbegin());
}
for(int i = 0; i < (int)minAns.size(); ++i) printf("%d ", minAns[i]);
printf("\n");
for(int i = 0; i < (int)maxAns.size(); ++i) printf("%d ", maxAns[i]);
printf("\n");
}
struct Que{
int val;
int pos;
Que(int v, int p):val(v), pos(p){}
Que(){}
};
Que maxQue[maxn];
Que minQue[maxn];
// C++ 12432K 5454MS
void solve2()
{
vector<int> maxAns, minAns;
int minHead = 0, minTail = 0;
int maxHead = 0, maxTail = 0;
for(int i = 0; i < k; ++i){
while(minHead < minTail && minQue[minTail - 1].val >= a[i]) --minTail;
minQue[minTail++] = Que(a[i], i);
while(maxHead < maxTail && maxQue[maxTail - 1].val <= a[i]) --maxTail;
maxQue[maxTail++] = Que(a[i], i);
}
for(int i = k; i < n; ++i){
maxAns.push_back(maxQue[maxHead].val);
minAns.push_back(minQue[minHead].val);
// 处理单调递增队列
while(minHead < minTail && i - minQue[minHead].pos >= k) ++minHead; //队头删除
while(minHead < minTail && minQue[minTail - 1].val >= a[i]) --minTail; //队尾插入
minQue[minTail++] = Que(a[i], i);
// 处理单调递减队列
while(maxHead < maxTail && i - maxQue[maxHead].pos >= k) ++maxHead; //队头删除
while(maxHead < maxTail && maxQue[maxTail - 1].val <= a[i]) --maxTail; //队尾插入
maxQue[maxTail++] = Que(a[i], i);
}
maxAns.push_back(maxQue[maxHead].val);
minAns.push_back(minQue[minHead].val);
for(int i = 0; i < (int)minAns.size(); ++i) printf("%d ", minAns[i]);
printf("\n");
for(int i = 0; i < (int)maxAns.size(); ++i) printf("%d ", maxAns[i]);
printf("\n");
}
int main()
{
while(cin >> n >> k){
for(int i = 0; i < n; ++i) scanf("%d", a + i);
solve2();
}
return 0;
}