【模板】 滑动窗口

传送门

题意

长度为(n)的序列,只能看到长度为(k)的滑动窗口,从数组的最左边移动到最右边,求滑动过程中每个滑动窗口的最大值和最小值

数据范围

(1leq nleq 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("");
}
原文地址:https://www.cnblogs.com/hhyx/p/13711185.html