【单调队列】滑动窗口
Time Limit:10000MS Memory Limit:65536K
Total Submit:232 Accepted:112
Case Time Limit:1000MS
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
Source
poj 2823
可以构造一个递增序列和递减序列,当窗口滑动到一个新位置时,对于自增序列需要维护它的单调性,则如果新元素比队尾元素小队尾元素就出队列(因为没有存在的意义了)。然后判断队列首的元素是否还在窗口内,找到第一个在窗口内的就是满足条件的该窗口的最小数据。
对于窗口内的最大数据可以采用类似的处理方法。
以求窗口中最大值为例
此问题单调递减队列操作方法:
1.若队尾元素小于要加入的元素,
删除队尾元素,直到队尾元素不小
于新加入的元素或者队列为空
2.讨论队首元素的下标是否在窗口
范围以内,若不在,删除队首。
3.当前队首元素即是当前窗口的最大值
注意:可用二分法优化算法
假如当前入队元素为x;
1.用二分法找出队列中比x大的第一个元素y;
2.将队列中y以后的所有元素都从队列中删除;
3.x入队;
注意:若找不到比x大的元素,则全部删除,然后x入队
#include<cstdio>
#include<deque>
#include<iostream>
using namespace std;
inline void _read(int &xx){
char tt=getchar();bool asd=false;
while((tt<'0'||tt>'9')&&tt!='-')tt=getchar();
if(tt=='-')asd=true,tt=getchar();
for(xx=0;tt>='0'&&tt<='9';tt=getchar())xx=xx*10+(tt-'0');
if(asd==true)xx=0-xx;
}
struct wk{
int num;
int id;
};
deque<wk>bger;
deque<wk>smer;
int n,k,s[1000005];
int maxx[1000005],minn[1000005];
int cax=0,cit=0;
void push_bg(int x,int y){
wk temp;
temp.num=x;
temp.id=y;
bger.push_back(temp);
}
void push_sm(int x,int y){
wk temp;
temp.num=x;
temp.id=y;
smer.push_back(temp);
}
int main(){
_read(n);
_read(k);
int i,j;
for(i=1;i<=n;i++)_read(s[i]);
push_bg(s[1],1);
push_sm(s[1],1);
for(i=2;i<=k;i++){
while(!smer.empty()&&s[i]>=smer.back().num)smer.pop_back();
push_sm(s[i],i);
while(!bger.empty()&&s[i]<=bger.back().num)bger.pop_back();
push_bg(s[i],i);
}
maxx[++cax]=smer.front().num;
minn[++cit]=bger.front().num;
for(i=k+1;i<=n;i++){
while(!smer.empty()&&s[i]>=smer.back().num)smer.pop_back();
push_sm(s[i],i);
while(!bger.empty()&&s[i]<=bger.back().num)bger.pop_back();
push_bg(s[i],i);
while(smer.front().id<=i-k)smer.pop_front();
maxx[++cax]=smer.front().num;
while(bger.front().id<=i-k)bger.pop_front();
minn[++cit]=bger.front().num;
}
for(i=1;i<=cit;i++)printf("%d ",minn[i]);
printf("\n");
for(i=1;i<=cax;i++)printf("%d ",maxx[i]);
}