POJ 2823 - Sliding Window(单调队列)
题目链接 https://cn.vjudge.net/problem/POJ-2823
【题意】
给你一个长度为n的序列a[1],a[2]…a[n]和一个整数k,求数列bi=min{a[i],a[i+1],…a[i+k-1]},和数列ci=max{a[i],a[i+1],…a[i+k-1]},i=1,2,…n-k+1(1<=k<=n<=1e6,0<=a[i]<=1e9)
【思路】
单调队列的模板题,单调队列最基础的应用就是处理滑动窗口的最值问题,可以用双端队列deque实现,把这道题当作模板记录下来,时间复杂度为O(n)
#include<cstdio>
#include<queue>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1000050;
int n,k;//序列长度,窗口大小
int a[maxn];
deque<int> minq,maxq;//最小值,最大值的单调队列
int Max[maxn],Min[maxn];
void getMin(){//计算最小值
minq.clear();
for(int i=1;i<k;++i){
while(minq.size() && a[minq.back()]>=a[i]) minq.pop_back();
minq.push_back(i);
}
for(int i=1;i<=n-k+1;++i){
int j=i+k-1;
while(minq.size() && minq.front()<i) minq.pop_front();
while(minq.size() && a[minq.back()]>=a[j]) minq.pop_back();
minq.push_back(j);
Min[i]=a[minq.front()];
}
}
void getMax(){//计算最大值
maxq.clear();
for(int i=1;i<k;++i){
while(maxq.size() && a[maxq.back()]<=a[i]) maxq.pop_back();
maxq.push_back(i);
}
for(int i=1;i<=n-k+1;++i){
int j=i+k-1;
while(maxq.size() && maxq.front()<i) maxq.pop_front();
while(maxq.size() && a[maxq.back()]<=a[j]) maxq.pop_back();
maxq.push_back(j);
Max[i]=a[maxq.front()];
}
}
int main(){
while(scanf("%d%d",&n,&k)==2){
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
getMin();
getMax();
for(int i=1;i<=n-k+1;++i){
printf("%d%c",Min[i],i==n-k+1?'\n':' ');
}
for(int i=1;i<=n-k+1;++i){
printf("%d%c",Max[i],i==n-k+1?'\n':' ');
}
}
return 0;
}
用数组模拟双端队列会更快
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1000005;
int n,k;
int a[maxn];
int q[maxn],s,t;
int Min[maxn],Max[maxn];
void getMin(){
s=t=0;
for(int i=1;i<=k-1;++i){
while(s<t && a[q[t-1]]>=a[i]) --t;
q[t++]=i;
}
for(int j=k;j<=n;++j){
int i=j-k+1;
while(s<t && q[s]<i) ++s;
while(s<t && a[q[t-1]]>=a[j]) --t;
q[t++]=j;
Min[i]=a[q[s]];
}
}
void getMax(){
s=t=0;
for(int i=1;i<=k-1;++i){
while(s<t && a[q[t-1]]<=a[i]) --t;
q[t++]=i;
}
for(int j=k;j<=n;++j){
int i=j-k+1;
while(s<t && q[s]<i) ++s;
while(s<t && a[q[t-1]]<=a[j]) --t;
q[t++]=j;
Max[i]=a[q[s]];
}
}
int main(){
while(scanf("%d%d",&n,&k)==2){
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
getMin();
getMax();
for(int i=1;i<=n-k+1;++i) printf("%d%c",Min[i],i==n-k+1?'\n':' ');
for(int i=1;i<=n-k+1;++i) printf("%d%c",Max[i],i==n-k+1?'\n':' ');
}
return 0;
}