Description
Window position | Minimum value | Maximum value |
---|---|---|
[1 3 -1] -3 5 3 6 7 | -1 | 3 |
1 [3 -1 -3] 5 3 6 7 | -3 | 3 |
1 3 [-1 -3 5] 3 6 7 | -3 | 5 |
1 3 -1 [-3 5 3] 6 7 | -3 | 5 |
1 3 -1 -3 [5 3 6] 7 | 3 | 6 |
1 3 -1 -3 5 [3 6 7] | 3 | 7 |
Your task is to determine the maximum and minimum values in the sliding window at each position.
Input
Output
Sample Input
8 3 1 3 -1 -3 5 3 6 7
Sample Output
-1 -3 -3 -3 3 3 3 3 5 5 6 7
思路:
1. 单调队列
2. 单调队列里存储原数组的下标
3. 假如是最大单调队列, 每次加入元素前, 待加入元素与队尾元素做比较, 假如待加入元素较大, 那么删除当前队尾元素, 重复比较, 直到可以加入.
4. 操作背后隐藏的原理是: 窗口每次移动都会引入一个新元素, 剔除一个旧元素. 窗口中已经存在的小于新元素的都要被踢出
总结:
1. ST, ED 初始化为 1 比较好
3. 看 discuss 说, ST 算法会超时
代码:
#include <iostream> using namespace std; const int MAXN = 1000010; int a[MAXN]; int window[MAXN]; int n, k; /* * 当心 k == 1 的情况 */ void printMin() { memset(window, 0, sizeof(window)); int head = 1, tail = 1; // 初始化为 0 for(int i = 1; i < k; i ++) { while(tail >= head && a[i] < a[window[tail]]) // 队列不为空, 且待加入元素小于队尾元素 tail--; window[++tail] = i; } for(int i = k; i <= n; i ++) { if(tail >= head && i-window[head] >= k) // 窗口移动, 删除最左边的元素 head++; while(tail >= head && a[i] < a[window[tail]]) tail--; window[++tail] = i; printf("%d ", a[window[head]]); } printf("\n"); } void printMax() { memset(window, 0, sizeof(window)); int head = 1, tail = 1; for(int i = 1; i < k; i ++) { while(tail >= head && a[i] > a[window[tail]]) tail--; window[++tail] = i; } for(int i = k; i <= n; i ++) { if(tail >= head && i-window[head] >= k) head++; while(tail >= head && a[i] > a[window[tail]]) tail--; window[++tail] = i; printf("%d ", a[window[head]]); } printf("\n"); } int main() { freopen("E:\\Copy\\ACM\\测试用例\\in.txt", "r", stdin); while(cin>>n >> k) { memset(a, 0, sizeof(a)); for(int i = 1; i <= n; i ++) { scanf("%d", &a[i]); } // mainFunc printMin(); printMax(); } return 0; }