对应POJ题目:点击打开链接
Time Limit: 12000MS | Memory Limit: 65536K | |
Total Submissions: 42356 | Accepted: 12503 | |
Case Time Limit: 5000MS |
Description
The array is [1 3 -1 -3 5 3 6 7], and k is 3.
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");
}
}
一维RMQ(1):
#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"); } }