【模板】 滑动窗口
传送门
题意
长度为\(n\)的序列,只能看到长度为\(k\)的滑动窗口,从数组的最左边移动到最右边,求滑动过程中每个滑动窗口的最大值和最小值
数据范围
\(1\leq n\leq 10^{6}\)
题解
-
单调队列中存下标,判断窗口长度,当求窗口中的最小值时,如果队列中存在两个元素,满足 \(a_{i} \geq a_{j}\)且\(i<j\),那么\(a_{i}\)不会被选为最小值,出队;
-
此时队列中剩下的元素严格单调递增,所以队头就是整个队列中的最小值,可以用\(O(1)\)的时间找到;
-
为了维护队列的这个性质,我们在往队尾插入元素之前,先将队尾大于等于当前数的元素全部弹出即可;
- 这样所有数均只进队一次,出队一次,所以时间复杂度是\(O(n)\)的
Code
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
const int N = 1e6+10;
int a[N];
int que[N];
int main()
{
int n,k;
cin>>n>>k;
rep(i,1,n+1)
scanf("%d",&a[i]);
int hh=1,tt=0;
rep(i,1,n+1)
{
if(hh <= tt && i - k + 1 > que[hh]) hh++;
while(hh<=tt && a[que[tt]] >= a[i]) tt--;
que[++tt] = i;
if(i > k - 1)
printf("%d " ,a[que[hh]]);
}
puts("");
hh=1,tt=0;
rep(i,1,n+1)
{
if(hh <= tt && i - k + 1 > que[hh]) hh++;
while(hh <= tt && a[que[tt]] <= a[i]) tt--;
que[++tt] = i;
if(i-k+1>0)
printf("%d " ,a[que[hh]]);
}
puts("");
}