《算法竞赛从入门到国奖》算法基础:数据结构-单调队列

💡Yupureki:个人主页

✨个人专栏:《C++》 《算法》《Linux系统编程》《高并发内存池》


🌸Yupureki🌸的简介:


目录

前言

[1. 【模板】单调队列 / 滑动窗口](#1. 【模板】单调队列 / 滑动窗口)

算法原理

代码实现

[2. 质量检测](#2. 质量检测)

算法原理

代码实现


前言

单调队列,顾名思义,就是存储的元素要么单调递增 要么单调递减 的队列。注意,这里的队列和普通的队列不一样,是一个双端队列,因此在数据结构上,我们一般选择deque

单调队列⼀般用于解决滑动窗口内最大值最小值问题,以及优化动态规划

1. 【模板】单调队列 / 滑动窗口

题目链接:

P1886 【模板】单调队列 / 滑动窗口 - 洛谷

算法原理

窗口内最大值:

从左往右遍历元素,维护一个单调递减的队列:

当前元素进队之后,注意维护队列内的元素在大小为k的窗口内;

此时队头元素就是最大值。

窗口内最小值:

从左往右遍历元素,维护一个单调递增的队列:

当前元素进队之后,注意维护队列内的元素在大小为k的窗口内;

此时队头元素就是最小值。

注意:

单调队列中一般用于滑动窗口 求最大值或最小值,那么当滑动窗口移动时,还要移除不在窗口中的元素 ,具体实现方案:在队列中存储数组元素的下标 ,当新元素从队尾入队列后,他就是新的队尾,也是最新的元素,如果 队尾元素的下标 - 队首元素的下标 >= 滑动窗口大小,则直接让队首出列

cpp 复制代码
while (q.back() - q.front() >= k)
      q.pop_front();

代码实现

cpp 复制代码
#include <iostream>
#include <vector>
#include <deque>
using namespace std;

int main()
{
    int n,k; cin >> n >> k;
    vector<int> v;
    deque<int> q;
    for (int i = 0; i < n; i++)
    {
        int num; cin >> num;
        v.push_back(num);
    }
    for (int i = 0; i < n; i++)
    {
        while (q.size() && v[q.back()] > v[i])
            q.pop_back();
        q.push_back(i);
        while (q.size() && q.back() - q.front() >= k)
            q.pop_front();
        if(i >= k -1 && i < n)
            cout << v[q.front()] << " ";
    }
    while (q.size())
        q.pop_front();
    cout << endl;
    for (int i = 0; i < n; i++)
    {
        while (q.size() && v[q.back()] < v[i])
            q.pop_back();
        q.push_back(i);
        while (q.size() && q.back() - q.front() >= k)
            q.pop_front();
        if (i >= k -1  && i < n)
            cout << v[q.front()] << " ";
    }
    return 0;
}

2. 质量检测

题目链接:

P2251 质量检测 - 洛谷

算法原理

滑动窗口求最小值,用递减的单调队列

代码实现

cpp 复制代码
#include <iostream>
#include <vector>
#include <deque>
using namespace std;

int main()
{
    int n, m; cin >> n >> m;
    vector<int> v;
    for (int i = 0; i < n; i++)
    {
        int num; cin >> num;
        v.push_back(num);
    }
    deque<int> q;
    for (int i = 0; i < n; i++)
    {
        while (q.size() && v[q.back()] > v[i])
            q.pop_back();
        q.push_back(i);
        while (q.back() - q.front() >= m)
            q.pop_front();
        if (i >= m-1)
            cout << v[q.front()]<<endl;
    }
    return 0;
}
相关推荐
半个落月6 小时前
从递归到快速排序:用 JavaScript 把分治思想讲明白
javascript·算法·面试
小月土星7 小时前
JavaScript 快速排序:从 pivot、双指针到分治思想
javascript·算法·面试
小月土星7 小时前
JavaScript 递归入门:从 1 到 n 求和,再到数组扁平化
javascript·算法·面试
To_OC1 天前
LC 1 两数之和:面试第一道必考题,暴力解法直接被面试官 pass
javascript·算法·leetcode
鱼鱼不愚与1 天前
《原来如此 | 第01期:为什么导航软件能预测红绿灯倒计时?》
算法
博客18001 天前
酷宝的使用方法,超好用的免费界面库,C++、MFC可用
c++·mfc·界面库·库来帮·酷宝
郝学胜_神的一滴1 天前
CMake 026:属性体系精讲、四大作用域全解 & 实战代码落地
c++·cmake
复杂网络1 天前
论最小 Agent 计算机的形态
算法
kisshyshy2 天前
🍦 雪糕、食堂、火车厢:三幅漫画吃透栈、队列与链表
javascript·算法