对应POJ题目:点击打开链接
Time Limit: 12000MS | Memory Limit: 65536K | |
Total Submissions: 42356 | Accepted: 12503 | |
Case Time Limit: 5000MS |
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
题意:给出n个数,求从左往右每k个数的最值。
思路1:单调队列
可在队首和队尾删除元素,在队尾插入元素。以递增队列(即队首元素最小,队列严格递增)为例,队尾删除元素:从队尾往前扫,一直pop掉不比e小的元素,e入队;队首删除元素:当队尾元素跟队首元素在原数组里的距离大于k时,就删除队首元素。
如本例:1 3 -1 -3 5 3 6 7
0 1 2 3 4 5 6 7
1、(1,0)
2、(1,0)(3,1)
3、(-1,2)
4、(-3,3)
5、(-3,3)(5,4)
6、(-3,3)(3,5)
7、(3,5)(6,6)//这里在加入(6,6)时把(-3,3)pop掉是因为6和-3这两个元素的距离len = 4 > k
8、(3,5)(6,6,)(7,7)
由于每一次入队都保证了队首元素为最小值,所以从第k次开始,每一次的队首元素就是样例输出的最小值。最大值求法类似。
思路2:线段树。就是线段树的区间最值
思路3:RMQ。
使用二维RMQ肯定超内存。由于题目区间长度固定,所以可以用滚动数组的方法,所以使用一维就可以了。可以有两种表示方法:
1)dp[i]表示从下标i开始数的长度为2^m个数的最值,其中2^m 为小于k的最大值。
2)dp[i]表示代替原来的dp[i][j](dp[i][j]表示从下标i开始数的长度为2^j个数的最值,其中2^j 为小于k的最大值。)
思路4:堆~(这部分知识待补)
优化:听说可以在I/O流中做文章,即缓存输入与无缓存输入(这部分知识待补)
单调队列:
#include <stdio.h> #include <stdlib.h> #include <string.h> #define M 1000005 int a[M]; int que[M]; int front, rear; int p[M]; int fp, rp; #define Front que[front] #define Rear que[rear-1] #define Push(x, i) que[rear++] = x, p[rp++] = i #define Pop front++, fp++ #define Pop_back rear--, rp-- #define Clearque front = rear = fp = rp = 0 #define Lengthque p[rp-1] - p[fp] + 1 #define Emptyque (front == rear ? 1 : 0) void SolveMin(int *A, int n, int k) { int i; front = rear = fp = rp = 0; for(i = 0; i < n; i++){ if(Emptyque && A[i] < Front) Clearque; else while(Rear >= A[i] && !Emptyque) Pop_back; Push(A[i], i); if(Lengthque > k) Pop; if(i >= k - 1){ printf("%d", Front); if(i < n - 1) printf(" "); } } printf("\n"); } void SolveMax(int *A, int n, int k) { int i; front = rear = fp = rp = 0; for(i = 0; i < n; i++){ if(Emptyque && A[i] > Front) Clearque; else while(Rear <= A[i] && !Emptyque) Pop_back; Push(A[i], i); if(Lengthque > k) Pop; if(i >= k - 1){ printf("%d", Front); if(i < n - 1) printf(" "); } } printf("\n"); } int main() { //freopen("in.txt", "r", stdin); int n, k; int i, j; while(~scanf("%d%d", &n, &k)) { for(i = 0; i < n; i++) scanf("%d", &a[i]); SolveMin(a, n, k); SolveMax(a, n, k); } }
#include <stdio.h> #include <stdlib.h> #include <string.h> #define M 1000005 #define MAX(x, y) ((x) > (y) ? (x) : (y)) #define MIN(x, y) ((x) < (y) ? (x) : (y)) int a[M]; int Max[M<<2]; int Min[M<<2]; int B[M]; int S[M]; typedef struct { int b, s; }Point; void Build(int root, int left, int right) { if(left == right - 1){ Max[root] = Min[root] = a[left]; return; } int mid = (left + right)>>1; Build(root<<1, left, mid); Build(root<<1|1, mid, right); Max[root] = MAX(Max[root<<1], Max[root<<1|1]); Min[root] = MIN(Min[root<<1], Min[root<<1|1]); } Point Query(int root , int left, int right, int l, int r) { Point P, P1; if(l <= left && right <= r){ P.b = Max[root]; P.s = Min[root]; return P; } int mid = (left + right)>>1; int b1, b2; if(r <= mid) return Query(root<<1, left, mid, l, r); else if(l >= mid) return Query(root<<1|1, mid, right, l, r); else{ P = Query(root<<1, left, mid, l, mid); P1 = Query(root<<1|1, mid, right, mid, r); Point p; p.b = MAX(P.b, P1.b); p.s = MIN(P.s, P1.s); return p; } } int main() { //freopen("in.txt", "r", stdin); int n, k, u; int i; while(~scanf("%d%d", &n, &k)) { for(i = 0; i < n; i++) scanf("%d", &a[i]); Build(1, 0, n); u = 0; Point P; for(i = 0; i + k <= n; i++){ P = Query(1, 0, n, i, i + k); B[u] = P.b; S[u++] = P.s; } printf("%d", S[0]); for(i = 1; i < u; i++) printf(" %d", S[i]); printf("\n"); printf("%d", B[0]); for(i = 1; i < u; i++) printf(" %d", B[i]); printf("\n"); } }
#include <stdio.h> #include <stdlib.h> #include <math.h> #include <string.h> #define M 1010000 #define MAX(x, y) ((x) > (y) ? (x) : (y)) #define MIN(x, y) ((x) < (y) ? (x) : (y)) int Max[M]; int Min[M]; int main() { //freopen("in.txt", "r", stdin); int n, k, val; int i, j, limit; while(~scanf("%d%d", &n, &k)) { for(i = 0; i < n; i++){ scanf("%d", &val); Max[i] = Min[i] = val; } for(j = 1; (j<<1) < k; j <<= 1) for(i = 0; i + (j<<1) - 1 < n; i++){ Max[i] = MAX(Max[i], Max[i+j]); Min[i] = MIN(Min[i], Min[i+j]); } printf("%d", MIN(Min[0], Min[k-j])); for(i = 1; i + k -1 < n; i++){ printf(" %d", MIN(Min[i], Min[i+k-j])); } printf("\n"); printf("%d", MAX(Max[0], Max[k-j])); for(i = 1; i + k -1 < n; i++){ printf(" %d", MAX(Max[i], Max[i+k-j])); } printf("\n"); } }一维RMQ(2):
#include <stdio.h> #include <stdlib.h> #include <math.h> #include <string.h> #define M 1000005 #define MAX(x, y) ((x) > (y) ? (x) : (y)) #define MIN(x, y) ((x) < (y) ? (x) : (y)) int a[M]; int Max[M]; int Min[M]; void caldp(int n, int limit) { int i, j; int r1, r2; for(i=0; i<n; i++) Max[i] = Min[i] = a[i]; for(j=1; j<=limit; j++){ //注意这个要在外层 for(i=0; i<n; i++){ if(i+(1<<j)-1 < n){ //Max[i][j] = MAX(Max[i][j-1], Max[i+(1<<(j-1))][j-1]); //Min[i][j] = MIN(Min[i][j-1], Min[i+(1<<(j-1))][j-1]); Max[i] = MAX(Max[i], Max[i+(1<<(j-1))]); Min[i] = MIN(Min[i], Min[i+(1<<(j-1))]); } } } } int rmq_max(int limit, int l, int r) { return MAX(Max[l], Max[r-(1<<limit)+1]); } int rmq_min(int limit, int l, int r) { return MIN(Min[l], Min[r-(1<<limit)+1]); } int main() { //freopen("in.txt", "r", stdin); int n, k, u; int i, limit; while(~scanf("%d%d", &n, &k)) { for(i = 0; i < n; i++) scanf("%d", &a[i]); limit = log(double(k)) / log(2.0); caldp(n, limit); printf("%d", rmq_min(limit, 0, k - 1)); for(i = 1; i + k <= n; i++){ printf(" %d", rmq_min(limit, i, i + k - 1)); } printf("\n"); printf("%d", rmq_max(limit, 0, k - 1)); for(i = 1; i + k <= n; i++){ printf(" %d", rmq_max(limit, i, i + k - 1)); } printf("\n"); } }