跳转至

滑动窗口/单调队列

前置知识

数组,用数组实现队列,单调性

目标

单调队列模板题

What

学过计算机网络的同学,都知道滑动窗口协议(Sliding Window Protocol),该协议是 TCP协议 的一种应用,用于网络数据传输时的流量控制,以避免拥塞的发生。该协议允许发送方在停止并等待确认前发送多个数据分组。由于发送方不必每发一个分组就停下来等待确认。因此该协议可以加速数据的传输,提高网络吞吐量。

滑动窗口算法其实和这个是一样的,只是用的地方场景不一样,可以根据需要调整窗口的大小,有时也可以是固定窗口大小。

滑动窗口算法在一个特定大小的字符串或数组上进行操作,而不在整个字符串和数组上操作,这样就降低了问题的复杂度,从而也达到降低了循环的嵌套深度。其实这里就可以看出来滑动窗口主要应用在数组和字符串上。

单调队列,是一种内部元素具有单调性的队列,可以解决“区间内最值”等问题。

How

模拟窗口,滑动。在滑动的过程中,维护窗口区间内的最值

例题,1597:【 例 1】滑动窗口

题意:滑动窗口位于每个位置时,窗口内的最大值和最小值是多少 思考: 1.暴力怎么做 2.队列当中有没有无用的值,怎么去掉 3.删掉多余的值,构造单调性 4.有了单调性,就有了极值,就优化了问题

#include <bits/stdc++.h>

using namespace std;

const int N = 1e6 + 10;

int a[N], q[N], n, k;
int hh, tt;

int main(){
    cin >> n >> k;
    for (int i = 0; i < n; i++) scanf("%d", &a[i]);

    hh = 0, tt = -1;
    for (int i = 0; i < n; i++){
        // 窗口滑出去了
        if (hh <= tt && i - k + 1 > q[hh]) hh++; 

        // 为了保证递增的单调性,从后往前,把比a[i]大的,全部弹出,然后把a[i]入队
        while (hh <= tt && a[q[tt]] >= a[i]) tt--;

        q[++tt] = i;

        // 窗口是满的就输出,没满k宽度的时候,是不可输出的
        // 队列是单调递增的,队头是窗口里的最小值
        if (i - k + 1 >= 0) printf("%d ", a[q[hh]]);
    }
    puts("");

    hh = 0, tt = -1;
    for (int i = 0; i < n; i++){
        // 窗口滑出去了
        if (hh <= tt && i - k + 1 > q[hh]) hh++; 

        // 为了保证递减的单调性,从后往前,把比a[i]小的,全部弹出,然后让a[i]入队
        while (hh <= tt && a[q[tt]] <= a[i]) tt--;

        q[++tt] = i;

        // 窗口是满的就输出,没满k宽度的时候,是不可输出的
        if (i - k + 1 >= 0) printf("%d ", a[q[hh]]);
    }
    puts("");


    return 0;
}

题单

总结

提高组入门算法

参考

滑动窗口算法基本原理与实践

AcWing