滑动窗口/单调队列

这篇博客介绍了如何利用单调队列优化算法来解决寻找序列中滑动窗口最大值和最小值的问题。通过构建递增队列输出最小值和递减队列输出最大值,实现了在O(n)的时间复杂度内完成求解,有效地提高了效率。文中还给出了具体的C++代码实现作为示例。
摘要由CSDN通过智能技术生成

有一个长为 n 的序列 a,以及一个大小为 k 的窗口。现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值。

要构造单调递增以及单调递减队列,分别按以下思路进行:
递 增 队 列 ( 输 出 最 小 值 ) { 若 待 插 入 队 列 的 元 素 小 于 队 尾 元 素 , 则 弹 出 队 尾 元 素 直 到 待 插 入 元 素 大 于 等 于 队 尾 元 素 为 止 若 待 插 入 元 素 大 于 等 于 队 尾 元 素 , 则 直 接 插 入 该 元 素 递增队列(输出最小值)\left\{\begin{array}{l} 若待插入队列的元素小于队尾元素,则弹出队尾元素直到待插入元素大于等于队尾元素为止 \\ \\若待插入元素大于等于队尾元素,则直接插入该元素 \end{array}\right.

递 减 队 列 ( 输 出 最 大 值 ) { 若 待 插 入 队 列 的 元 素 大 于 队 尾 元 素 , 则 弹 出 队 尾 元 素 直 到 待 插 入 元 素 小 于 等 于 队 尾 元 素 为 止 若 待 插 入 元 素 小 于 等 于 队 尾 元 素 , 则 直 接 插 入 该 元 素 递减队列(输出最大值)\left\{\begin{array}{l} 若待插入队列的元素大于队尾元素,则弹出队尾元素直到待插入元素小于等于队尾元素为止 \\ \\若待插入元素小于等于队尾元素,则直接插入该元素 \end{array}\right.

#include <cstdio>
#include <cstring>

const int maxn = 1000005;

struct monque {
    int n, k, head, tail;
    int a[maxn], q[maxn], p[maxn];
    
    void read()
    {
        scanf("%d%d", &n, &k);
        for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    }
    
    void monque_min()
    {
        head = 1;
        tail = 0;
        for (int i = 1; i <= n; i++) {
            while (head <= tail && q[tail] >= a[i]) tail--;
            q[++tail] = a[i];
            p[tail] = i;
            while (p[head] <= i - k) head++;
            if (i >= k) printf("%d ", q[head]);
        }
        printf("\n");
    }
    
    void monque_max()
    {
        head = 1;
        tail = 0;
        for (int i = 1; i <= n; i++) {
            while (head <= tail && q[tail] <= a[i]) tail--;
            q[++tail] = a[i];
            p[tail] = i;
            while (p[head] <= i - k) head++;
            if (i >= k) printf("%d ", q[head]);
        }
        printf("\n");
    }
} Monque;

int main()
{
    Monque.read();
    Monque.monque_min();
    Monque.monque_max();
    return 0;
}

参考 https://www.luogu.com.cn/blog/hankeke/solution-p1886

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值