题目:
有一个长为 n 的序列 a,以及一个大小为 k 的窗口。现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值。
思路:
维护单调队列,求窗口最大值,即为单调递减队列,保证队头都是此时窗口的最大值,若后入队的元素比队尾的大,则在该元素的存活期间,队尾的那个元素永远不会成为最大值,所以,队尾元素出队,该元素入队。并且每次都需要维护窗口k,若超过,队头往右移动。同理可推得窗口最小值的情况。
代码:
#include<bits/stdc++.h>
using namespace std;
long long a[1000005],tmp[1000005];//a为序列,tmp记录序列元素的位置
long long qa[1000005],qb[1000005];//qa存最小值,qb存最大值
int main()
{
int n,k;
scanf("%d %d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
int head=1,tail=0;
for(int i=1;i<=n;i++)
{
while(head<=tail&&qa[tail]>=a[i]) tail--;//维护单调递减队列
qa[++tail]=a[i];
tmp[tail]=i;//记录序列元素位置
while(tmp[head]<=i-k) head++;//窗口超出,队头右移
if(i>=k) printf("%lld ",qa[head]);
}
printf("\n");
head=1;
tail=0;
for(int i=1;i<=n;i++)
{
while(head<=tail&&qb[tail]<=a[i]) tail--;
qb[++tail]=a[i];
tmp[tail]=i;
while(tmp[head]<=i-k) head++;
if(i>=k) printf("%lld ",qb[head]);
}
return 0;
}