1. 程式人生 > 實用技巧 >【模板】 滑動視窗

【模板】 滑動視窗

傳送門

題意

長度為\(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;
const int N=1e5+10;
int n,k;
int a[N];
int que[N],tt,hh=1;
int main(){
    cin>>n>>k;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    for(int i=1;i<=n;i++){
        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)
            cout<<a[que[hh]]<<' ';
    }
    cout<<endl;
    hh=1,tt=0;
    for(int i=1;i<=n;i++){
        if(hh<=tt && i-k+1>que[hh]) hh++;
        while(hh<=tt && a[que[hh]]<=a[i]) tt--;
        que[++tt]=i;
        if(i-k+1>0)
            cout<<a[que[hh]]<<' ';
    }
    cout<<endl;
}