用单调队列来解决滑动窗口问题(P1886)

我们主打的就是一个单调队列

解题步骤与解释都放在注释里面了,几乎每一步都有注释

希望我的注释可以对你有所帮助!

#include <iostream>
#include <deque>
using namespace std;

const int N = 1000005;
int a[N];
deque<int>q;   //  队列中的数据实际上是元素在元序列中的位置

int main()
{
    int n, m;
    cin >> n >> m;
    //  n是所有的数的个数,m是窗口的大小
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];//  把数字都输进去
    }
    //  下面开始用单调队列来把每一个窗口里面的最小的数输出出来
    for (int i = 0; i < n; i++)
    {
        while (!q.empty() && a[q.back()] > a[i])
        {
            q.pop_back();   
            //  每当窗口放进去一个新的值之前
            //  要把这个要新加入的值和我们单调队列的队尾的值相比较
            //  如果队尾的值没有这个值大,那么便ok,如果队尾的值确实比这个值大,那就把队尾pop
            //  接着将这个要加入的值与新的队尾进行比较,知道队尾不用在pop之后,便停止(或者把整个单调队列的值都pop完)
        }
        q.push_back(i);  //  插入新的值
        //  上面的操作让我们实现了队列的单调性,那么下面我们来实现“窗口”
        if (i >= m-1)  //  避免了一开始窗口还不成型
        {
            while (!q.empty() && q.front() <= i - m)   //  注意这里的不等号是小于等于!!!
            {
                // 那么为什么是i-m?
                // 我们要理解,我们的单调序列绝对不是我们的窗口
                // 这个题实际上就没有窗口
                q.pop_front();
                // 这个操作是为了保证当前输出的最小值是当前窗口的最小值!!!!
                // 是这样的,每个窗口里面的最左边的值的下标就是i-m
                // 我们这样做是为了把不是这个窗口的数的下标排出去,以防止输出不是当前窗口的数
            }
            cout << a[q.front()] << ' ';
        }
    }
    //  我们输出完了最小值,再输出最大值
    cout << '\n';
    //  我们先清理一下我们的单调序列
    q.clear();
    //  建立for循环,开始往单调序列里面放下标
    for (int i = 0; i < n; i++)
    {
        while (!q.empty() && a[q.back()] < a[i])
        {
            q.pop_back();   //  之前是把小的放前面,现在是把大的放前面
        }
        q.push_back(i);
        if (i >= m-1)  //  窗口已经成型,那就可以开始输出了
        {
            while (!q.empty() && q.front() <= i - m)   //  注意这里的不等号是小于等于!!!
            {
                q.pop_front();
            }
            cout << a[q.front()] << ' ';
        }
    }
    cout << '\n';
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值