单调队列 | 线段树 | 一维RMQ —— POJ 2823
来源:互联网 发布:c语言打开文件并写入 编辑:程序博客网 时间:2024/06/11 10:03
对应POJ题目:点击打开链接
Description
The array is [1 3 -1 -3 5 3 6 7], and k is 3.
Your task is to determine the maximum and minimum values in the sliding window at each position.
Input
Output
Sample Input
8 31 3 -1 -3 5 3 6 7
Sample Output
-1 -3 -3 -3 3 33 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 1000005int 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");}}
- 单调队列 | 线段树 | 一维RMQ —— POJ 2823
- POJ 2823 线段树 Or 单调队列
- HDU3183 A Magic Lamp —— 贪心(单调队列优化)/ RMQ / 线段树
- Poj 2823 Sliding Window (单调队列 or 线段树)
- poj 2823 Sliding Window (单调队列 or 线段树)
- poj 2823 Sliding Window 单调队列或线段树
- POJ 2823 Sliding Window(单调队列||线段树)
- poj 2823 滑动窗口 单调队列/线段树
- poj 2823 Sliding Windows 线段树|单调队列
- POJ - 2823 Sliding Window(单调队列RMQ)
- POJ 2823 线段树,RMQ
- pku 2823(单调队列、线段树)
- 双端队列(单调队列)POJ 2823 定长区间最小值(RMQ也可以)
- POJ 2823 Sliding Window 双端队列 or RMQ or 线段树
- poj 2823 Sliding Window (线段树,RMQ)
- Poj 2823 (单调队列)
- poj 2823【单调队列】
- POJ 2823 单调队列
- cesiumjs开发实践(三)
- 第六周项目一 深复制体验(2)
- 轻量级程序编辑器的选择:EmEditor、Editplus等---Web开发系列之工具篇
- C语言typeof详解
- iOS开发之通知机制——UIDevice通知、键盘通知
- 单调队列 | 线段树 | 一维RMQ —— POJ 2823
- Servlet和JSON传送与接收
- Boost Asio库的学习与探究(二)
- cesiumjs开发实践(四)
- 数字图像处理均衡化灰度拉伸C++实现
- SQL some key word
- 第三章第十题三角形面积20150418
- 数据结构(C语言版)课后习题1.2霍纳规则
- java中的&&(且)用法误区