题意:滑窗问题。一个长度为n的序列,分别求前k个数中的最值,第2个到第k + 1个数中的最值,...,直到最后一个元素。
解法:单调队列。对于求最小值来说,题中的样例k为3,序列为为
1 3 -1 -3 5 3 6 7
每次放入数字前,检查队头的编号,看是否已经超过了滑窗的范围,如果超过了弹出队头;还要看队尾元素是否比将要放入的数字大,因为新放入的数字如果比较小那么之前放入的大的数字肯定不可能是答案了,所以要弹出。这两个操作完成后再放入新插入的元素。此时队头元素即为当前滑窗的答案。
样例解释为:
队列 答案
1 -
1 3 -
-1 -1
-3 -3
-3 5 -3
-3 3 -3
3 6 3
3 6 7 3
代码:
用了双端队列……勉强水过……用数组模拟更快……然而我比较懒……嗯哼
#include<stdio.h> #include<iostream> #include<algorithm> #include<string> #include<string.h> #include<math.h> #include<limits.h> #include<time.h> #include<stdlib.h> #include<map> #include<queue> #include<set> #include<stack> #include<vector> #include<deque> #define LL long long using namespace std; const int MAXN = 1000005; struct node { int v, pos; node(int v, int pos) : v(v), pos(pos) {} node() {} }num[MAXN]; int ans1[MAXN], ans2[MAXN]; deque <node> maxn, minn; int main() { int n, k; while(~scanf("%d%d", &n, &k)) { for(int i = 0; i < n; i++) { scanf("%d", &num[i].v); num[i].pos = i; } int ans = 0; for(int i = 0; i < n; i++) { if(!minn.empty() && minn.front().pos <= i - k) minn.pop_front(); while(!minn.empty() && minn.back().v >= num[i].v) minn.pop_back(); minn.push_back(num[i]); if(i >= k - 1) { ans = minn.front().v; ans1[i - k + 1] = ans; } while(!maxn.empty() && maxn.back().v <= num[i].v) maxn.pop_back(); if(!maxn.empty() && maxn.front().pos <= i - k) maxn.pop_front(); maxn.push_back(num[i]); if(i >= k - 1) { ans = maxn.front().v; ans2[i - k + 1] = ans; } } for(int i = 0; i < n - k + 1; i++) { if(i) printf(" "); printf("%d", ans1[i]); } puts(""); while(!minn.empty()) minn.pop_back(); for(int i = 0; i < n - k + 1; i++) { if(i) printf(" "); printf("%d", ans2[i]); } puts(""); while(!maxn.empty()) maxn.pop_back(); } return 0; }