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

💡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;
}
相关推荐
旖-旎几秒前
《LeetCode647 回文子串 || LeetCode 5 最长回文子串》
c++·算法·leetcode·动态规划·哈希算法
Darkwanderor40 分钟前
对Linux的进程控制的研究
linux·运维·c++
云泽8081 小时前
从零吃透 C++ 异常:抛出捕获、栈展开、异常重抛与编码规范详解
开发语言·c++·代码规范
轻颂呀1 小时前
约瑟夫环问题
算法
REDcker1 小时前
libdatachannel 快速入门
c++·webrtc·datachannel
凤凰院凶涛QAQ2 小时前
《Java版数据结构 & 集合类剖析》栈与队列:“push/pop 是栈的灵魂,offer/poll 是队列的骨架——四组 API,两种人生”
java·开发语言·数据结构
科技大视界3 小时前
投资AI项目,传统尽调不够用了——李章虎律师拆解算法、数据、算力三大雷区
人工智能·算法·数据挖掘
second603 小时前
第一部分:快速上手 —— 建立 C++ 基本语法与编程范式
开发语言·c++
郝学胜-神的一滴3 小时前
算法实战:最小k个数——大顶堆的优雅解法
开发语言·数据结构·c++·python·程序人生·算法·排序算法
Irissgwe3 小时前
算法滑动窗口
数据结构·算法