Description
给你一个长度为N(N<=10^6)的数组,一个长为K的滑动的窗体从最左移至最右端,你只能见到窗口的K个数,每次窗体向右移动一位,找出窗体所包含的数字的最大和最小值,如下表所示:k的值为3
窗口位置 最小值 最大值
[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
Input
第1行为n,k,第2行为长度为n的数组。
Output
共2行,第1行是每个位置的min value,第2行是每个位置的max value。
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.当前队首元素即是当前窗口的最大值
求最小值方法同上。
【问题】
加入元素时,有两个方案:
1.直接从队尾开始一个个地删,直到满足加入当前元素,队列单调性不变。
2.二分查找,找到从右往左第一个大于当前元素的数,插入它的后面。
显然方案2要科学很多,但是我想了想,第一个方案最多删去n个,不会影响总的时间复杂度,还是O(n)。
不会证明。。。
【代码】
#include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<ctime> #include<iostream> #include<algorithm> using namespace std; int N,K,v[1000005]; int Q[1000005],Qt[1000005]; int ans1[1000005],ans2[1000005],tot; void _in(int &x) { bool mark=false; char t; t=getchar(); while((t!='-')&&(t<'0'||t>'9')) t=getchar(); if(t=='-') { mark=true; t=getchar(); while(t<'0'||t>'9') t=getchar(); } for(x=t-'0',t=getchar();'0'<=t&&t<='9';x=x*10+t-'0',t=getchar()); if(mark) x=-x; } void _init() { _in(N);_in(K); for(int i=1;i<=N;i++) _in(v[i]); } void _solve() { int head=1,tail=2; Q[1]=v[1]; Qt[1]=1; for(int i=2;i<=K;i++) { while(v[i]>=Q[tail-1]&&tail-1>=1) tail--; Q[tail]=v[i]; Qt[tail++]=i; } tot=0; ans1[++tot]=Q[head]; for(int i=K+1;i<=N;i++) { while(v[i]>=Q[tail-1]&&tail-1>=head) tail--; Q[tail]=v[i]; Qt[tail++]=i; while(Qt[head]<=i-K&&head<tail) head++; ans1[++tot]=Q[head]; } head=1;tail=2; memset(Q,0,sizeof(Q)); memset(Qt,0,sizeof(Qt)); Q[1]=v[1]; Qt[1]=1; for(int i=2;i<=K;i++) { while(v[i]<=Q[tail-1]&&tail-1>=1) tail--; Q[tail]=v[i]; Qt[tail++]=i; } tot=0; ans2[++tot]=Q[head]; for(int i=K+1;i<=N;i++) { while(v[i]<=Q[tail-1]&&tail-1>=head) tail--; Q[tail]=v[i]; Qt[tail++]=i; while(Qt[head]<=i-K&&head<tail) head++; ans2[++tot]=Q[head]; } for(int i=1;i<=tot;i++) printf("%d ",ans2[i]); printf("\n"); for(int i=1;i<=tot;i++) printf("%d ",ans1[i]); printf("\n"); } int main() { _init(); _solve(); return 0; }