AcWing154. 滑动窗口https://www.acwing.com/problem/content/description/156/
思路:滑动窗口,利用单调队列维护最大值和最小值。我们定义队列的头为head,尾为tail,q1为维护最小值的队列,q2为维护最大值的队列。
求最大值时,有三个步骤:
1.维护head。当head<=tail同时head+k<=i,表明已经不在窗口范围内了,head++
2.维护tail。当head<=tail同时a[q2[tail]]<a[i],即队列的尾部已经小于a[i],已经不是窗口范围内的最大值了,那么令尾部出队,tail--.
3.将新来的元素入队
4.如果i>=k了,依次输出最大值,即a[q2[head]]。
最小值同理。
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1000010;
int n,m,sum;
int q1[maxn],q2[maxn],a[maxn];
void min_queue(){
int head = 1,tail = 0;
for(int i=1;i<=n;i++){
while(head<=tail&&q1[head]+m<=i) head++;//过时了,用不上了,队首出列
while(head<=tail&&a[q1[tail]]>a[i]) tail--;//队尾比后面的数大,根本不可能是最小的,所以队尾出列
q1[++tail]=i;//将新来的入队
if(i>=m) printf("%d ",a[q1[head]]);
}
printf("\n");
}
void max_queue(){
int head = 1,tail = 0;
for(int i=1;i<=n;i++){
while(head<=tail&&q2[head]+m<=i) head++;//过时了,队首出队
while(head<=tail&&a[q2[tail]]<a[i]) tail--;//队尾比新来的小,不可能是最大的,队尾出队
q2[++tail]=i;
if(i>=m) printf("%d ",a[q2[head]]);
}
printf("\n");
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
min_queue();
max_queue();
return 0;
}