单调队列(C/C++)

news2025/1/10 12:08:36

引言:

单调队列和单调栈都是一种数据结构,应用十分广泛,在蓝桥杯、ICPC、CCPC等著名编程赛事都是重点的算法,今天博主将自己对单调栈与单调队列的理解以及刷题的经验,用一篇博客分享给大家,希望对大家有所帮助,它们用于解决类似“寻找最大值与最小值”这样的问题。它们的区别在于如何维护数据的单调性。

  1. 单调栈(Monotonic Stack):

    • 单调栈是一种栈数据结构,只能在栈顶进行插入和删除操作。
    • 单调栈的特点是栈中的元素按照一定的单调性排列,常用的有单调递增和单调递减。
    • 在插入新元素时,如果新元素破坏了当前的单调性,则从栈顶删除一部分元素,直到满足单调性要求。这样可以保证栈中的元素保持单调性。
    • 单调栈的典型应用是在寻找下一个更大/更小元素的问题。
  2. 单调队列(Monotonic Queue):

    • 单调队列是一个双端队列,支持在队列两端进行插入和删除操作。
    • 单调队列的特点是队列中的元素按照一定的单调性排列,常用的有单调递增和单调递减。
    • 在插入新元素时,如果新元素破坏了当前的单调性,则在队尾删除一部分元素,直到满足单调性要求。这样可以保证队列中的元素保持单调性。
    • 单调队列的典型应用是在滑动窗口中寻找最大/最小值的问题。

单调队列和单调栈都是用于维护数据的单调性,但单调队列是双端队列,用于在滑动窗口中寻找最大/最小值,而单调栈是栈数据结构,用于寻找下一个更大/更小元素

接上篇单调栈,下面我们对单调队列进行深度解析


单调队列:

单调队列是一种特殊的队列数据结构,用于解决一些与序列相关的问题。单调队列中的元素按照其值的大小有序排列,同时还满足队列的先进先出的性质。

单调队列的主要特点是,队列中的元素始终保持一个单调性,可以是递增或递减。这意味着,当有新的元素入队时,队列会自动进行调整,将不符合要求的元素删除。

单调队列的应用场景主要是解决滑动窗口相关的问题。滑动窗口是指在一个序列中,窗口以固定大小向右滑动,每次滑动一个位置。在每个滑动窗口中,需要对窗口中的元素进行一些操作。

使用单调队列可以在O(n)的时间复杂度内解决滑动窗口问题。具体的操作过程如下:

  1. 首先,将窗口的前k个元素依次入队;
  2. 与队列尾部的元素进行比较,将比当前元素小的元素从队列尾部依次出队,直到队列尾部的元素大于等于当前元素,或者队列为空;
  3. 判断队列的头部元素是否已经超出了滑动窗口的范围,如果超出了,则将队列头部元素出队;
  4. 将当前元素入队;
  5. 对每个滑动窗口,都可以通过队列的头部元素获取到当前窗口的最大(最小)值。

总之,单调队列是一种高效解决滑动窗口问题的数据结构,它可以在O(n)的时间复杂度内完成操作。同时,单调队列也有一些其他的应用场景,如求滑动窗口中的最小值、最大值等。

如下图:滑动窗口为3,模拟单调队列入队可以一下过程。

单调队列是一种特殊的队列,它可以在 O(1) 时间内完成以下两种操作:

1. 在队尾插入元素 x。
2. 在队头删除元素。

单调队列常用于求解滑动窗口中的最值问题,例如求最大值、最小值或其他满足特定条件的值。

下面是一些单调队列的具体应用场景

1. 求滑动窗口的最大值/最小值:给定一个数组 nums 和一个滑动窗口的大小 k,需要找出每个滑动窗口里的最大值或最小值。使用单调队列可以在 O(n) 时间内解决这个问题。

2. 求滑动窗口中的最大值与最小值的差值不超过一个给定值的个数:给定一个数组 nums、一个滑动窗口的大小 k,以及一个给定值 maxDiff,需要找出滑动窗口中最大值与最小值的差值不超过 maxDiff 的窗口个数。

3. 求滑动窗口中的最大子数组和:给定一个数组 nums 和一个正整数 k,需要找出滑动窗口中长度为 k 的连续子数组的最大和。

4. 求滑动窗口中的第 k 大的元素:给定一个数组 nums 和一个正整数 k,需要找出滑动窗口中第 k 大的元素。

这些是单调队列的应用场景之一,还有其他一些问题也可以使用单调队列解决。单调队列的核心思想是维护一个递增或递减的队列,通过在队尾插入元素和在队头删除元素来保持队列的单调性。这样就可以在 O(1) 时间内获取滑动窗口中的最值或其他满足条件的值。


模板奉上:

第一种使用STL
        deque<int>q;//滑动窗口
        for(int i = 0; i < nums.size(); i++){
        while(!q.empty()&&nums[q.back()]<nums[i])//维护队列单调性(递增)
                q.pop_back();
            q.push_back(i);//入队
            if(!q.empty() && i-q.front() >= k)//判断队头是否需要出队
                q.pop_front();
            if(i >= k-1){
                //在此处寻找最大值,以及代码扩展
                res.push_back(nums[q.front()]);//取队头作为窗口最大元素
            }
        }
        return res;
第二种自己手写一个
        int h=-1,t=0;
        int q[1005];
        vector<int> res;
        for(int i=0;i<nums.size();i++){
            while(h<=t&&a[q[t]]<=nums[i])t--;//队尾不满足单调性出队
            q[++t]=i;//入队
            if(q[h]<i-k+1)h++;//队头超出窗口,出队
            if(i-k+1>=0) res.push_back(nums[q[h]]);//此处代码扩展
        }
        return res;


实战演练——单调队列习题

滑动窗口最大值

79. 滑动窗口的最大值 - AcWing题库高质量的算法题库icon-default.png?t=N7T8https://www.acwing.com/problem/content/description/75/

class Solution {
public:
    vector<int> maxInWindows(vector<int>& nums, int k) {
        int q[100001];
        int hh=0,tt=0;
        vector<int> ans;
        for(int i=0;i<nums.size();i++)
        {
            while(hh<=tt&&nums[q[tt]]<=nums[i]) tt--;//新元素不满足单调递增,队尾出队
            q[++tt]=i;//新元素入队
            if(q[hh]<i-k+1) hh++;//队头不再窗口内
            if(i-k+1>=0) ans.push_back(nums[q[hh]]);//窗口内元素个数大于等于k,可进行操作
        }
        return ans;
    }
};

滑动窗口【模板】 

滑动窗口 /【模板】单调队列 - 洛谷icon-default.png?t=N7T8https://www.luogu.com.cn/problem/P1886

使用双端队列实现(deque):
#include<bits/stdc++.h>
#define N 1000005
using namespace std;
int n,k;
int a[N];
deque<int> q;//使用双端队列
int main()
{
	cin>>n>>k;
	for(int i = 1;i<=n;i++)
		cin>>a[i];
	
	for(int i = 1;i<=n;i++)//求滑动窗口最小值
	{
		while(q.size() && q.back()>a[i])
			q.pop_back();
		
		q.push_back(a[i]); 
		if(i-k>=1 && q.front()== a[i-k])
			q.pop_front();
		
		if(i>=k)
			cout<<q.front()<<" "; 
		
	}
	cout<<"\n";
	q.clear();//清空防止影响求最大值
	
	for(int i = 1;i<=n;i++)//求滑动窗口最大值
	{
		while(q.size() && q.back()<a[i])
			q.pop_back();
		q.push_back(a[i]);
		
		if(i-k>=1 && q.front() == a[i-k])
			q.pop_front();
		
		if(i>=k)
			cout<<q.front()<<" ";
	}
	return 0;
}
手写一个:
#include<iostream>
using namespace std;
const int N=1e6+5;
int h,t;
int n,k;
int a[N],q[N];
int main(){
	cin>>n>>k;
	for(int i=0;i<n;i++){
		cin>>a[i];
	}
	h=0,t=-1;
	for(int i=0;i<n;i++){
		while(h<=t&&a[q[t]]>=a[i])t--;
		q[++t]=i;
		if(q[h]<i-k+1)h++;
		if(i-k+1>=0)cout<<a[q[h]]<<" ";
	}
	cout<<endl;
	h=0,t=-1;
	for(int i=0;i<n;i++){
		while(h<=t&&a[q[t]]<=a[i])t--;
		q[++t]=i;
		if(q[h]<i-k+1)h++;
		if(i-k+1>=0)cout<<a[q[h]]<<" ";
	}
	return 0;
}

多重背包问题(单调队列优化)

6. 多重背包问题 III - AcWing题库高质量的算法题库icon-default.png?t=N7T8https://www.acwing.com/problem/content/6/这里可以看一下我专门写的多重背包问题的博客,这里不再介绍

细谈多重背包问题-CSDN博客


总结:

单调队列是一种非常有用的数据结构,可以高效地解决需要维护窗口内最值的问题。使用单调队列的时间复杂度为O(n),其中n为输入数组的长度。其实现方式有双向队列和单调栈两种,根据具体问题的要求选择适合的实现方式即可,文章尚有不足,恳请各位大佬指出,博主不胜感激,感谢大家支持。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1604730.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

springboot中mongodb连接池配置-源码分析

yml下spring.data.mongodb 以前mysql等在spring.xxx下配置&#xff0c;现在springboot新版本&#xff08;小编3.2.3&#xff09;在spring.data.xxx下了&#xff0c;如下所示&#xff0c;mongodb的配置在spring.data.mongodb下&#xff1a; 连接池相关参数配置-源码分析 拼接在…

使用CCS软件查看PID曲线

在刚开始学习PID的时候&#xff0c;都需要借助PID的曲线来理解比例&#xff0c;积分&#xff0c;微分这三个参数的具体作用。但是这些曲线生成一般都需要借助上位机软件或者在网页上才能实现。如果是在单片机上调试程序的话&#xff0c;想要看曲线&#xff0c;一般就是通过串口…

C语言 【基础语法】

一、编程环境搭建 编译器&#xff1a;gcc 集成开发环境&#xff1a;vscode 1.1 安装vscode 1.2 设置中文包 插件 1.3 设置C/C扩展 安装 C/C Compile Run extension 和 C/C Extension Pack 扩展 二、基础语法 2.1 第一个c语言程序 2.2 数据类型 2.2.1 变量的语法(重点) …

氯氟氰虫酰胺杀灭活性好成本低 目前全球市场规模小

氯氟氰虫酰胺杀灭活性好成本低 目前全球市场规模小 氯氟氰虫酰胺&#xff0c;通用名为cyhalodiamide&#xff0c;是一种双酰胺类杀虫剂&#xff0c;外观为白色固体粉末状。 氯氟氰虫酰胺属于鱼尼丁受体作用剂&#xff0c;为邻苯二甲酰胺结构的双酰胺类杀虫剂&#xff0c;作用机…

Vision Transformer (ViT)浅析

Vision Transformer (ViT) 概述 为了将Transformer引入视觉任务&#xff0c;Google团队开发出了Vision Transformer (ViT)&#xff0c;其中ViT模型以及变种在图像分类任务上一骑绝尘 ViT的结构 ViT首先将图像( R H W C \mathbb{R}^{H\times W\times C} RHWC)划分为多个Patc…

一周学会Django5 Python Web开发-Django5模型数据新增

锋哥原创的Python Web开发 Django5视频教程&#xff1a; 2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~共计46条视频&#xff0c;包括&#xff1a;2024版 Django5 Python we…

上位机图像处理和嵌入式模块部署(树莓派4b实现动态插件)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 和上位机一样&#xff0c;我们的智能硬件如果想应用到更多的场景&#xff0c;那么势必需要实现更多的算法。这些算法和算法之间最好是松散耦合的插…

思维导图软件Xmind for Mac 中文激活版 支持M

XMind是一款非常受欢迎的思维导图软件&#xff0c;它应用了Eclipse RCP软件架构&#xff0c;注重易用性、高效性和稳定性&#xff0c;致力于帮助用户提高生产率。 Xmind for Mac 中文激活版下载 XMind的程序主体由一组插件构成&#xff0c;包括一个核心主程序插件、一组Eclipse…

公众号开发:获取域名

公众号中的基本配置要求需要连接服务器地址&#xff0c;这个服务器地址必须是域名&#xff0c;但是域名需要进行购买&#xff0c;因此可以使用到一个内网穿透工具&#xff1a;ngrok 进行测试 国内的就可以了Sunny-Ngrok内网转发内网穿透 - 国内内网映射服务器 首先花两块钱实名…

Mybatis之SqlNodeSqlSource

SqlNode SqlNode接口 apply()是SqlNode 接口中定义的唯一方法&#xff0c;该方法会根据用户传入的实参&#xff0c; 参数解析该SqlNode所记录的动态SQL节点&#xff0c;并调用DynamicContext.appendSql()方法将解析后的SQL片段追加到DynamicContext.sqlBuilder中保存。当SQL节…

[Collection与数据结构] 二叉树(二):二叉树精选OJ例题(上)

1. 判断是否为相同的二叉树 OJ链接 public boolean isSameTree(Node p, Node q) {if (p null && q ! null || p ! null && q null){//结构不同return false;}if (p null && q null){//结构相同,都是空树return true;}if (p.value ! q.value){//…

机器人流量激增:恶意机器人活动升级与新型规避技术挑战企业安全防御

近日&#xff0c;根据Cyber News引用Thales Imperva Bad Bot发布的最新研究报告&#xff0c;揭示了一个令人警醒的现象&#xff1a;2023年&#xff0c;互联网总流量中的49.6%由机器人贡献&#xff0c;相较于上一年增长了2%&#xff0c;创下了自2013年监测以来的历史新高。这一显…

希亦、固特、大宇超声波清洗机值不值得买?宝藏机型测评争霸

在当代生活的快节奏中&#xff0c;眼镜成了我们不可或缺的伙伴&#xff0c;无论是助力视力的提升还是时尚造型的加分项。然而&#xff0c;许多人忽视了眼镜清洁的重要性&#xff0c;不知道不清洗眼镜会带来诸多危害&#xff0c;从而影响健康和生活质量。长时间累积的污垢、油脂…

苹果开发初学者指南:Xcode 如何为运行的 App 添加环境变量(Environmental Variable)

概览 Xcode 15 在运行 SwiftUI 代码时突然报告如下警告&#xff1a; Error: this application, or a library it uses, has passed an invalid numeric value (NaN, or not-a-number) to CoreGraphics API and this value is being ignored. Please fix this problem. 不仅如此…

【智能算法】花朵授粉算法(FPA)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献 1.背景 2012年&#xff0c;Yang等人受到自然界花朵授粉过程启发&#xff0c;提出了鸭群算法&#xff08;Flower Pollination Algorithm, FPA&#xff09;。 2.算法原理 2.1算法思想 FPA基于自然界花朵授…

idea项目启动异常:Command line is too long.

项目场景&#xff1a; 提示&#xff1a;这里简述项目相关背景&#xff1a; idea中启动项目报错&#xff1a; 解决方案 在idea 的运行配置中&#xff0c;修改enviroment下的shorten command line 为jar manifest 注&#xff1a; 有时shorten command line 可能不是默认存在的…

Kafka复习

消息中间件的作用: 异步处理: 与并行相比,虽然减少了时间,但是还是得等待其他线程执行完,但是消息中间件对于简单的业务处理,还要引入一个中间件也比较复杂如果我投递了简历之后需要发送成功邮件以及短信,就可以交给消息中间件就像数据库、redis数据一致性,需要用到延迟…

揭秘网上问卷调查:多样化类型助力数据收集

在当今数字化时代&#xff0c;问卷调查作为一种便捷、高效的数据收集和分析方式&#xff0c;被广泛运用于市场调研、学术研究、消费者反馈等领域。而在网上进行问卷调查更是提高了调查效率和覆盖范围&#xff0c;因此&#xff0c;了解网上的问卷调查类型对于设计合适的调查问卷…

如何使用Postgres的JSONB数据类型进行高效查询

文章目录 解决方案1. 创建包含JSONB列的表2. 插入JSON数据3. 使用GIN索引加速查询4. 执行高效的JSONB查询 示例代码解释 PostgreSQL的JSONB数据类型提供了一种灵活的方式来存储和查询JSON格式的数据。JSONB不仅允许你在PostgreSQL数据库中存储JSON文档&#xff0c;而且还对这些…

万字长文带你APK反编译重签名aabapks转换

Android反编译 反编译&#xff08;Decompilation&#xff09;是将已编译的程序&#xff08;比如二进制代码&#xff09;转换回更高级别的编程语言代码的过程。这通常用于理解程序的工作原理&#xff0c;进行软件审计&#xff0c;恢复丢失的源代码&#xff0c;或者进行教学研究…