题目链接
Time Limit: 12000MS | Memory Limit: 65536K | |
Total Submissions: 39725 | Accepted: 11747 | |
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
Source
题意:数n个数的数列a 。求所有长度为K的区间的最大值和最小值。
题解:单调队列的基本运用。我们让区间,最开始为a数列前k个数,每次后移一位。先谈最大值的情况,由于区间不断后移,若当前区间中, i>j 且 ai > aj ,那么aj 一定不能成为后面的区间的最优解。利用这个性质,我们可以维护一个单调的双端队列,队列里面存可能成为最优解的数。
队列里面的数要满足两个单调性,元素的数值按从大到小排列,元素在a数列中的下标按从小到大排列。这样队首元素为当前区间的最优值。
插入操作:插入的数下标一定比队尾大。假设插入的数大于队尾,那么插入的数一定比队尾更优,删除队尾,直到队尾元素大于插入的数或队列为空,将数插入队列。在插入操作中保证队列的两个单调性。
删除操作:随着区间的移动,我们要将队列里面不在区间里的数删除。由于下标按最小到大排列的,所以我们从队首开始删除,直至队首满足条件。
求最小值同理。
由于每个数插入、删除的复杂度为O(1),只入队和出队一次,所以总复杂度O(n)。
代码如下:
#include<stdio.h> #include<algorithm> #include<queue> #include<stack> #include<map> #include<set> #include<vector> #include<iostream> #include<string.h> #include<string> #include<math.h> #include<stdlib.h> #define inff 0x3fffffff #define eps 1e-8 #define nn 1100000 #define mod 1000000007 typedef long long LL; const LL inf64=LL(inff)*inff; using namespace std; int n,k; int a[nn]; int ans1[nn],ans2[nn]; int que1[nn],que2[nn]; int l1,r1,l2,r2; void add1(int id) { while(r1>l1) { if(a[que1[r1-1]]<=a[id]) { r1--; } else { que1[r1++]=id; return ; } } que1[r1++]=id; } void dele1(int id) { while(l1<r1) { if(que1[l1]<=id) l1++; else break; } } void add2(int id) { while(l2<r2) { if(a[que2[r2-1]]>=a[id]) { r2--; } else { que2[r2++]=id; return ; } } que2[r2++]=id; } void dele2(int id) { while(l2<r2) { if(que2[l2]<=id) l2++; else break; } } int main() { int i; while(scanf("%d%d",&n,&k)!=EOF) { for(i=1;i<=n;i++) { scanf("%d",&a[i]); } l1=r1=l2=r2=0; int cnt=0; for(i=1;i<=k;i++) { add1(i); add2(i); } ans1[++cnt]=que1[l1]; ans2[cnt]=que2[l2]; for(i=k+1;i<=n;i++) { add1(i); add2(i); dele1(i-k); dele2(i-k); ans1[++cnt]=que1[l1]; ans2[cnt]=que2[l2]; } for(i=1;i<=cnt;i++) { printf("%d%c",a[ans2[i]],i==cnt?'\n':' '); } for(i=1;i<=cnt;i++) { printf("%d%c",a[ans1[i]],i==cnt?'\n':' '); } } return 0; }