题意
- 给定长为n序列,给定窗口长度k,问所有长为k的区间的最大值和最小值
思路
- 单调队列
- 并维护一个队列(以最大值为例),此队列中,队头表示的是当前窗口内的最大值,其他的是可能成为最大值的候选
- 同时,当新入队的元素比之前的元素大的时候,就意味着小的元素再也不可能成为最大值(生命周期没有新入队的长)
- 最终,窗口的左界扫到队首的时候就以为着队首生命周期结束
AC代码
#include<bits/stdc++.h>
using namespace std;
int a[2020200];
int main(){
int n,k;
scanf("%d%d",&n,&k);
for(int i=0;i<n;i++){scanf("%d",&a[i]);}
deque<int>mx,mn;
for(int l=0,r=0;l<n;l++){
while(r-l+1<=k&&r<n){
while(!mn.empty()&&mn.back()>a[r]){
mn.pop_back();
}
mn.push_back(a[r]);
r++;
}
if(r-l+1>k){
printf("%d ",mn.front());
if(a[l]==mn.front()){
mn.pop_front();
}
}
}
printf("\n");
//对于最大值,如果一个新增元素大于当前元素,当前元素就不可能再成为最大元素
for(int l=0,r=0;l<n;l++){
while(r-l+1<=k&&r<n){
while(!mx.empty()&&mx.back()<a[r]){
mx.pop_back();
}
mx.push_back(a[r]);
r++;
}
if(r-l+1>k){
printf("%d ",mx.front());
if(a[l]==mx.front()){
mx.pop_front();
}
}
}
return 0;
}
PS
- 写个双指针墨迹了半天,要想要窗口内有k个元素,最终窗口r-l+1会等于k+1,所以大于k的时候才做输出处理