【算法】单调队列

一、什么是单调队列

单调队列是一种数据结构,其特点是队列中的元素始终保持单调递增或递减,主要用于维护队列中的最小值或最大值

不同于普通队列只能从队头出队、队尾入队,单调队列为了维护其特征,还允许从队尾出队

不管怎么向单调队列中添加元素或删除元素,其单调性始终不变。这是如何做到的呢?我们用一道例题来说明

二、如何使用单调队列

2.1 滑动窗口问题

滑动窗口问题是单调队列的典型应用场景

简单来说,一个长度固定的窗口从序列开始一步步移动到结尾,我们要得到这个窗口每一步移动中其内部的最大值和最小值。

这个问题很简单,如果我们使用一个单调队列,窗口每次移动就将新元素入队,让其内部的元素保持单调递增,那么队头元素就是窗口的最小值,求最大值则保持单调递减即可

那我们该如何维护一个单调队列呢?首先来讲讲单调队列的思想

2.2 单调队列的思想

我们以上面例题中给出的序列 {1,3,-1,-3,5,3,6,7} 为例,窗口大小为3,单调队列大小和窗口一致

窗口从头开始向后移动,首先是1入队,然后是3入队,到这里单调队列内部都保持单调递增,于是我们不作处理

窗口继续向后移动,接下来是-1入队。但是-1入队后就打破了单调队列的单调性了,所以我们需要进行一些操作维护其单调性

因为我们选择保持队列单调递减,所以当有更小的元素要从队尾入队时,我们要把它前面所有比它更大的元素全都先从队尾出队

也就是说,当准备入队的元素更优时,我们需要先将前面造成干扰的元素出队,再将新元素入队。

此时,窗口已经完整的进入序列中了,可以开始拿到最值,此时单调队列的队头元素就是窗口中的最小值

窗口滑动,接下来-3准备入队。和前面的步骤一样,先将-1从队尾出队,然后-3入队

得到此时窗口最小值-3 

窗口滑动,接下来5正常入队

得到此时窗口最小值-3

窗口滑动,接下来3准备入队,和前面的步骤一样,先将5从队尾出队,然后3入队

得到此时窗口最小值-3

窗口滑动,接下来6正常入队

但是!此时单调队列中的-3已经滑出窗口范围了,需要出队

得到此时窗口最小值3

窗口滑动,接下来7正常入队

得到此时窗口最小值3

这就是单调队列完整的思想,如果要求窗口每个时刻的最大值,则将单调队列保持单调递减即可

2.3 实际解题过程

明白了单调队列的思想后,我们还需要学会如何在实际解题时使用它

在上面的例题中,我们可以用一个数组模拟单调队列,用两个下标 h 和 t 来维护队头和队尾

另外一个数组存储目标序列,len 表示窗口长度,i 表示窗口的右侧,则 i - len + 1就是窗口的左侧。通过i++就可以实现窗口滑动的效果

我们在单调队列中存储元素在原序列中的下标,这样做是为了便于判断一个元素仍在单调队列中但已经滑出窗口的情况(如果该元素的下标小于窗口左侧则说明已经滑出窗口,则出队)

用下标维护队列头尾的目的:采用伪删除法,将 t-- 就能达到队尾出队的效果,h++就能达到队头出队的效果

大概思路都讲完了,这里直接放出例题的代码

#include <iostream>
using namespace std;const int N = 1000010;int n, k;
int a[N];
int q[N];void winmin() //求窗口最小值
{int h = 1, t = 0; //h是队头,t是队尾,队列初始为空for(int i = 1;i <= n;i++) //i为窗口右端,i递增则窗口不断滑动{while(h <= t && a[q[t]] >= a[i]) //队列不为空且队尾元素比新元素大,出队t--; q[++t] = i; //存储下标方便判断队头出队if(q[h] < i - k + 1) h++; //队头存储的下标小于窗口左侧,队头元素滑出窗口if(i >= k) cout << a[q[h]] << " "; //打印窗口最小值}cout << endl;
}void winmax() //求窗口最大值
{int h = 1, t = 0;for(int i = 1;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) cout << a[q[h]] << " ";}cout << endl;
}int main()
{cin >> n >> k;for(int i = 1;i <= n;i++) //注意这里元素是从下标为1处开始存储cin >> a[i];winmin();winmax();return 0;
}

完.

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

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

相关文章

深入Linux:权限管理与常用命令详解

文章目录 ❤️Linux常用指令&#x1fa77;zip/unzip指令&#x1fa77;tar指令&#x1fa77;bc指令&#x1fa77;uname指令&#x1fa77;shutdown指令 ❤️shell命令以及原理❤️什么是 Shell 命令❤️Linux权限管理的概念❤️Linux权限管理&#x1fa77;文件访问者的分类&#…

【微信小程序知识点】getApp()全局数据共享,页面间通信,组件间通信

getApp()-全局数据共享 在小程序中&#xff0c;可以通过getApp()方法获取到小程序全局唯一的App实例。因此在App()方法中添加全局共享的数据&#xff0c;方法&#xff0c;从而实现页面&#xff0c;组件的数据传值。 // app.js App({//全局共享的数据globalData: {token: &qu…

力扣每日一题:3011. 判断一个数组是否可以变为有序

力扣官网&#xff1a;前往作答&#xff01;&#xff01;&#xff01;&#xff01; 今日份每日一题&#xff1a; 题目要求&#xff1a; 给你一个下标从 0 开始且全是 正 整数的数组 nums 。 一次 操作 中&#xff0c;如果两个 相邻 元素在二进制下数位为 1 的数目 相同 &…

Cxx Primer-CP-2

开篇第一句话足见作者的高屋建瓴&#xff1a;类型决定程序中数据和操作的意义。随后列举了简单语句i i j;的意义取决于i和j的类型。若它们都是整形&#xff0c;则为通常的算术意义。若它们都为字符串型&#xff0c;则为进行拼接操作。若为用户自定义的class类型&#xff0c;则…

为Linux设置GRUB密码

正文共&#xff1a;999 字 11 图&#xff0c;预估阅读时间&#xff1a;1 分钟 我们前面介绍了如何恢复root密码&#xff08;CentOS 7.9遗忘了root密码怎么办&#xff1f;&#xff09;&#xff0c;虽然简单好用&#xff0c;但是可能会被不法分子利用&#xff0c;造成root密码以及…

快速读出linux 内核中全局变量

查问题时发现全局变量能读出来会提高效率&#xff0c;于是考虑从怎么读出内核态的全局变量&#xff0c;脚本如下 f open("/proc/kcore", rb) f.seek(4) # skip magic assert f.read(1) b\x02 # 64 位def read_number(bytes):return int.from_bytes(bytes, little,…

【FineReport的详细使用教程】

前言&#xff1a; &#x1f49e;&#x1f49e;大家好&#xff0c;我是书生♡&#xff0c;今天主要和大家分享一下&#xff0c;BI报表中的FineRoport 的详细使用&#xff0c;以及它的优势&#xff01;&#xff01;&#xff01;希望对大家有所帮助。 &#x1f49e;&#x1f49e;代…

C# Winform布局控件的几种方式

在 C# WinForms 应用程序中&#xff0c;布局控件和布局管理器可以帮助开发者创建响应式的用户界面&#xff0c;即使在窗口大小改变时也能保持控件的正确位置和尺寸。 通常我们采用Panel和Dock&#xff0c;辅助Anchor实现类似如下的布局。 以下是几种常见的布局控件和方法&…

计算机网络通信

1、最原始的hub结构 2、局域网的交换机&#xff1a;mac和交换机端口路由表-数据链路层 mac地址 3、不同局域网之间进行通信&#xff0c;主要是路由器-网络层-ip 源ip到目标ip的不变化&#xff0c;但是mac地址在一直变化

Linux--信号量

线程系列&#xff1a; Linux–线程的认识(一) Linux–线程的分离、线程库的地址关系的理解、线程的简单封装&#xff08;二&#xff09; 线程的互斥&#xff1a;临界资源只能在同一时间被一个线程使用 生产消费模型 信号量 信号量&#xff08;Semaphore&#xff09;是在多线程…

基于PyTorch深度学习实践技术应用

近年来&#xff0c;Python语言由于其开源、简单等特点&#xff0c;受到了广大程序开发者的偏爱&#xff0c;丰富的函数库使得其在各行各业中得到了广泛的应用。伴随着新一轮人工智能&#xff08;尤其是深度学习&#xff09;的快速发展&#xff0c;许多深度学习框架应运而生&…

通义千问Qwen-VL-Chat大模型本地训练(二)

目录 前言 环境准备 软件安装 数据准备 模型训练 模型名称修改 数据集修改 模型参数修改 数据读取编码修改 output_dir修改 模型调用 验证 小结 前言 人工智能大模型是一种能够利用大数据和神经网络来模拟人类思维和创造力的人工智能算法。它利用海量的数据和深度学习技…

中职网络安全B模块Cenots6.8数据库

任务环境说明&#xff1a; ✓ 服务器场景&#xff1a;CentOS6.8&#xff08;开放链接&#xff09; ✓ 用户名&#xff1a;root&#xff1b;密码&#xff1a;123456 进入虚拟机操作系统&#xff1a;CentOS 6.8&#xff0c;登陆数据库&#xff08;用户名&#xff1a;root&#x…

【C++深度探索】全面解析多态性机制(二)

&#x1f525; 个人主页&#xff1a;大耳朵土土垚 &#x1f525; 所属专栏&#xff1a;C从入门至进阶 这里将会不定期更新有关C/C的内容&#xff0c;欢迎大家点赞&#xff0c;收藏&#xff0c;评论&#x1f973;&#x1f973;&#x1f389;&#x1f389;&#x1f389; 前言 我…

Debezium日常分享系列之:Debezium 3.0.0.Alpha1 Released

Debezium日常分享系列之&#xff1a;Debezium 3.0.0.Alpha1 Released 一、重大改变Java 和 Maven 要求已更改 二、新的特征和提高MongoDB 三、更多内容 Debezium 3 的第一个预发布版本 3.0.0.Alpha1。这个版本虽然比正常的预版本要小&#xff0c;但高度关注几个关键点&#xff…

《财经日报》︱揭秘随身WiFi市场乱象与格行的破局之路 格行如何树立行业清流新标杆? 随身WiFi真的靠谱吗?

在移动互联网高速发展的今天&#xff0c;随身WiFi以其便捷性和高性价比迅速成为市场宠儿。然而&#xff0c;随着行业的迅速扩张&#xff0c;一系列乱象与套路也逐渐浮出水面&#xff1a;从虚假宣传到限速虚量&#xff0c;随身WiFi行业中的种种套路让消费者防不胜防。商家利用信…

c语言题目之求两个整数的二进制位数的不同个数

文章目录 一、题目二、分析三、代码实现 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、题目 二、分析 首先看到这道题我们是求两个整数的二进制位不同位的个数&#xff0c;在操作符中我们详细学到到了按位操作符相关的内容&#xff0c;首先看到要…

三相感应电机建模仿真(5):考虑铁耗时静止dq坐标系的数学模型及其仿真模型

1.概述 2.考虑铁耗时的三相感应电机数学模型 3.考虑铁耗时的三相感应电机仿真模型 4.仿真实例 5.总结 6.参考文献 1.概述 电机的铁心损耗主要包括涡流损耗和磁滞损耗,这些损耗以热的形式消耗能量,减少了电动机的有效输出功率,对电机效率产生影响;铁心损耗会导致电机内…

【教程】Vue2中使用svg矢量图

1.npm导包 npm i svg-sprite-loader --save2.创建目录放入svg文件&#xff0c;创建SvgIcon.js 3.SvgIcon.js const req require.context(./svg, false, /\.svg$/) const requireAll requireContext > requireContext.keys().map(requireContext) requireAll(req)4.vue.c…