【模板】 滑动窗口

传送门

题意

长度为\(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("");
}
posted @ 2020-09-22 11:48  Hyx'  阅读(221)  评论(0编辑  收藏  举报