1 题意
给定一个整数序列和一个滑动窗口大小,让滑动窗口在整数序列上滑动,求出滑动窗口内的最小值和最大值。
链接:link。
2 思路
用单调队列维护窗口最大最小值。
单调队列分为最大队列和最小队列,其内部元素分别是单调递减和单调递增的,并用来维护窗口最大值和最小值。
下面说明一下如何用最大队列维护窗口最大值,最小队列则相反,这里不再介绍。
- 先判断队列首元素的位置与当前元素的位置之差是否大于窗口大小,如果大于则要将队首元素出队列
- 判断队尾元素是否小于或等于当前元素,如果是的话就将队尾元素出队列(这样可以保证队头永远是当前窗口最大的元素)
- 将当前元素入队列,并记录下该元素的位置,最后将队头元素记录下来即可(即为当前窗口的最大值)
2.1 时间复杂度分析
每个元素压入和弹出单调队列一次,所以时间复杂度为 O ( n ) \mathcal{O}(n) O(n)。
2.2 实现
#include<iostream>
#include<cstdio>
using namespace std;
const int MAXN=1e6+10;
int n,k,id[MAXN];
int val[MAXN],Fmax[MAXN],Fmin[MAXN];
int q[MAXN],head,tail;
void col_max(){
head=1;tail=0;
for(int i=1;i<=n;++i){
while(id[head]<i-k+1&&head<=tail) head++;
while(val[i]>=q[tail]&&head<=tail) tail--;
id[++tail]=i;q[tail]=val[i];
Fmax[i]=q[head];
}
}
void col_min(){
head=1;tail=0;
for(int i=1;i<=n;++i){
while(id[head]<i-k+1&&head<=tail) head++;
while(val[i]<=q[tail]&&head<=tail) tail--;
id[++tail]=i;q[tail]=val[i];
Fmin[i]=q[head];
}
}
int main(){
scanf("%d %d",&n,&k);
for(int i=1;i<=n;++i) scanf("%d",&val[i]);
col_max();col_min();
for(int i=k;i<=n;++i) printf("%d ",Fmin[i]);
printf("\n");
for(int i=k;i<=n;++i) printf("%d ",Fmax[i]);
printf("\n");
return 0;
}