【算法】单调队列单调栈

一、单调队列

   用来维护一段区间内的最大值或最小值,例如滑动窗口区间最值等问题。

基本概念

单调队列是一种存储数据的队列,其中元素的顺序是单调递增或单调递减的。在算法竞赛中,我们一般使用两个单调队列,一个维护单调递增序列,另一个维护单调递减序列。单调队列是一个双端队列

代码如下:

#include <iostream>
#include <deque>
#include <vector>
#include <algorithm>
using namespace std;void output(vector<int>& arr) {int n = arr.size(), len = 0;for (int i = 0; i < n; i++) len += printf("%3d", i);cout << "\n";for (int i = 0; i < len; i++)printf("-");cout << "\n";for (int i = 0; i < n; i++) len += printf("%3d", arr[i]);cout << "\n";
}int main(){int n, k;cin >> n >> k;vector<int> arr;deque<int> q;for (int i = 0, a; i < n; i++) {cin >> a;arr.push_back(a);}output(arr);for (int i = 0; i < n; i++) {while (!q.empty() && arr[q.back()] > arr[i])q.pop_back();q.push_back(i); //压入下标if (i - q.front() == k) q.pop_front(); //弹出队头printf("[%d, %d] = arr[%d] = %d \n",max(i - k + 1, 0), i,q.front(),arr[q.front()]);}
}

滑动窗口

154. 滑动窗口 - AcWing题库

滑动窗口是一类问题,需要在一个长度为n的序列中,找到所有长度为k的连续子序列中的最大值或最小值。使用单调队列可以在O(n)的时间复杂度内解决该问题。

具体做法如下:

(1)将前k个元素插入单调队列中,并记录队列的最大值或最小值。
(2)从第k+1个元素开始,每次将一个新的元素插入单调队列中。
(3)插入时,先将队列中所有小于等于该元素的队尾元素出队,保证队列中的元素单调递减。
(4)将该元素插入队尾,并记录队列的最大值或最小值。
(5)将长度为k的子序列的最大值或最小值输出即可。

方法1:(数组实现)

#include <iostream>
using namespace std;const int N = 1e6 + 10;
int q[N], a[N]; //数组q用来存下标
int main() {int n, k;cin >> n >> k;for (int i = 0; i < n; i++) cin >> a[i];//找滑动窗口最小值int hh = 0, tt = -1;for (int i = 0; i < n; i++) {if (i - q[hh] == k) hh++; //队头弹出元素while (hh <= tt && a[q[tt]] > a[i]) tt--; //队尾弹出元素q[++tt] = i; //压入下标if (i - k + 1 >= 0)printf("%d ", a[q[hh]]);}printf("\n");//找滑动窗口最大值hh = 0, tt = -1;for (int i = 0; i < n; i++) {if (i - q[hh] == k) hh++; //队头弹出元素while (hh <= tt && a[q[tt]] < a[i]) tt--; //队尾弹出元素q[++tt] = i; //压入下标if (i - k + 1 >= 0)printf("%d ", a[q[hh]]);}return 0;
}

方法2:(双端队列)

#include <iostream>
#include <deque>
#include <vector>
using namespace std;int main() {int n, k;cin >> n >> k;vector<int> arr(n);deque<int> q;for (int i = 0; i < n; i++)cin >> arr[i];for (int i = 0; i < n; i++) {if (i - q.front() == k) q.pop_front();while (!q.empty() && arr[q.back()] > arr[i])q.pop_back();q.push_back(i);if (i - k + 1 >= 0) cout << arr[q.front()] << " ";}cout << endl;q.clear();for (int i = 0; i < n; i++) {if (i - q.front() == k) q.pop_front();while (!q.empty() && arr[q.back()] < arr[i])q.pop_back();q.push_back(i);if (i - k + 1 >=0) cout << arr[q.front()] << " ";}return 0;
}

区间最值

135. 最大子序和 - AcWing题库

需要在一个长度为n的序列中,找到所有长度为k的子序列中的最大值或最小值。使用单调队列可以在O(n)的时间复杂度内解决该问题。

其实现方法与上面类似,但是需要注意:

  • 区间最值问题是在不限制子序列连续性的情况下,找到子序列中的最大值或最小值。
  • 而滑动窗口问题则是在限制子序列必须连续的情况下,找到所有长度为k的子序列中的最大值或最小值。

方法1:(数组实现)

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;typedef long long LL;const int N = 1e6 + 10;
int q[N];
LL s[N];
int main()
{int n, m;cin >> n >> m;//处理为前缀和序列for (int i = 1; i <= n; i++) {cin >> s[i];s[i] += s[i - 1];}LL res = -1e10;int hh = 0, tt = 0;for (int i = 1; i <= n; i++) {if (i - q[hh] > m) hh++;res = max(res, s[i] - s[q[hh]]);while (hh <= tt && s[q[tt]] >= s[i]) tt--;q[++tt] = i;}cout << res << "\n";return 0;
}

方法2:(双端队列)

#include <iostream>
#include <algorithm>
#include <cstring>
#include <deque>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long LL;int main()
{int n, m;cin >> n >> m;//处理前缀和vector<LL> s(n + 1);s.push_back(0);deque<LL> q;for (int i = 1; i <= n; i++) {cin >> s[i];s[i] += s[i - 1];}q.push_back(0);LL res = -1e6;for (int i = 1; i <= n; i++) {if (i - q.front() > m) q.pop_front();res = max(res, s[i] - s[q.front()]);while (!q.empty() && s[q.back()] >= s[i]) q.pop_back();q.push_back(i);}cout << res << "\n";return 0;
}


二、单调栈

基本概念

单调栈实际上就是栈,只是利用了一些巧妙的逻辑,使得每次新元素入栈后,栈内的元素都保持有序(单调递增或单调递减),即从队首不弹出元素的单调队列就是单调栈。

作用:用于找最近小于关系(单调递增)和最近大于关系(单调递减)

代码如下:

#include <iostream>
#include <stack>
#include <vector>
#include <algorithm>
using namespace std;void output(vector<int>& arr) {int n = arr.size(), len = 0;for (int i = 0; i < n; i++) len += printf("%3d", i);cout << "\n";for (int i = 0; i < len; i++)printf("-");cout << "\n";for (int i = 0; i < n; i++) len += printf("%3d", arr[i]);cout << "\n";
}int main(){int n;cin >> n;vector<int> arr;arr.push_back(-1); //假如极小值为-1stack<int> s;for (int i = 0, a; i < n; i++) {cin >> a;arr.push_back(a);}arr.push_back(-1); //假如极小值为-1vector<int> l(arr.size() + 1), r(arr.size() + 1);output(arr);//右侧for (int i = 0;  i < arr.size(); i++) {while (!s.empty() && arr[s.top()] > arr[i]) {r[s.top()] = i;s.pop();}s.push(i);}//左侧 (倒着扫描)while (!s.empty()) s.pop();for (int i = arr.size() - 1; i >= 0; i--) {while (!s.empty() && arr[s.top()] > arr[i]) {l[s.top()] = i;s.pop();}s.push(i);}for (int i = 1; i <= n; i++) {printf("arr[%d] = %d, right : arr[%d] = %d, left : arr[%d] = %d\n",i, arr[i],r[i], arr[r[i]],l[i], arr[l[i]]);}return 0;
}

数组实现单调栈:

830. 单调栈

#include <iostream>
using namespace std;
const int N = 10010;int stk[N], tt ;
int main()
{int n;cin >> n;while(n--){int x;cin>>x;while(tt&&stk[tt]>=x) tt--;if(tt==0) printf("-1 ");else printf("%d ",stk[tt]);stk[++tt]=x;}return 0;
}

三、总结

单调队列:擅长维护区间【最大/最小】值,最小值对应单调递增队列

单调栈:擅长维护最近【大于/小于】关系,

从左侧先入栈就是维护左侧最近关系

从右侧先入栈,就是维护右侧最近关系。

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

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

相关文章

【版面费优惠丨ACM独立出版丨接受全文摘要投稿】2024年生物医药和智能技术国际学术会议(ICBIT 2024,8月23-25)

“2024年生物医药和智能技术国际学术会议&#xff08;ICBIT 2024&#xff09;”拟定于2024年8月23-25日于珠海召开。近年来&#xff0c;智能技术已经逐渐走入生物医药领域&#xff0c;并在与生物医药领域的融合创新中凸显出巨大的发展潜力和社会价值。人工智能技术在生物医药领…

水处理基本知识

RO反渗透程序设计软件下载 水处理基本知识 纯水制备的核心工艺 核心工艺&#xff1a;纯水&#xff08;超纯水&#xff09;制备的主要处理工艺&#xff0c;结合前处理&#xff08;预处理&#xff09;工艺&#xff0c;辅助工艺及特殊工艺&#xff0c;组成完整的纯水制备工艺。结…

优质作品集秘诀:8个技巧让你的作品脱颖而出

制作一个高质量的投资组合不仅可以展示你的技能和创造力&#xff0c;还可以帮助你在求职和职业发展中脱颖而出。如何制作高质量的投资组合&#xff1f;今天给大家讲述作品集的 8 个实用技能&#xff0c;帮助你制作出令人印象深刻的作品集&#xff01; 1、精选作品 并不是所有…

飞睿智能会议室静止雷达人体检测传感器,实时监测使用状态,有人、无人智能感应节能减

在这个科技日新月异的时代&#xff0c;每一个细微的创新都可能成为推动行业创新的关键力量。今天&#xff0c;让我们聚焦于一项看似不起眼却实则潜力无限的技术——飞睿智能静止雷达人体检测传感器&#xff0c;以及它在会议室这一商务交流核心区域中的巧妙应用。想象一下&#…

前端Canvas入门——怎么用Canvas画一些简单的图案

Canvas作为前端的画图工具&#xff0c;其实用途还是蛮广泛的&#xff0c;但是很多前端学习课程其实都很少涉及到这块内容。 于是乎&#xff0c;就写下这个了。 当然啦&#xff0c;目前还在学习摸索中。 一些实战代码&#xff0c;仅供参考&#xff1a; <canvasid"ctx&…

EtherCAT总线冗余让制造更安全更可靠更智能

冗余定义 什么是总线冗余功能&#xff1f;我们都知道&#xff0c;EtherCAT现场总线具有灵活的拓扑结构&#xff0c;设备间支持线型、星型、树型的连接方式&#xff0c;其中线型结构简单、传输效率高&#xff0c;大多数的现场应用中也是使用这种连接方式&#xff0c;如下图所示…

【Qt课设】基于Qt实现的中国象棋

一、摘 要 本报告讨论了中国象棋程序设计的关键技术和方法。首先介绍了中国象棋的棋盘制作&#xff0c;利用Qt中的一些绘画类的函数来进行绘制。在创作中国象棋棋子方面&#xff0c;首先&#xff0c;我们先定义一下棋子类&#xff0c;将棋子中相同的部分进行打包&#xff0c;使…

idea推送到gitee 401错误

在idea上推送时遇到这样的问题&#xff0c;解决方法如下&#xff1a; 在https://的后面加上 用户名:密码 然后再提交就ok啦&#xff01;

三、SpringMVC

三、SpringMVC 1、SpringMVC简介 1.1、什么是MVC MVC是一种软件架构的思想&#xff0c;将软件按照模型、视图、控制器来划分 M&#xff1a;Model&#xff0c;模型层&#xff0c;指工程中的JavaBean&#xff0c;作用是处理数据 JavaBean分为两类&#xff1a; 一类称为实体…

代码随想录-Day55

42. 接雨水 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 输入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,2,1] 输出&#xff1a;6 解释&#xff1a;上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高…

CentOS7二进制安装和YUM安装mongodb,服务器无法安装5.0以上的 mongodb 数据库报错 Illegal instruction

文章目录 MongoDB 安装二进制安装YUM 安装 Tips:1、MongoDB安装问题2、MongoDB登录3、MongoDB排序时内存大小限制和创建索引4、创建用户5、Java yaml使用密码连接mongodb6、MongoDB增删改查 MongoDB 安装 二进制安装 [rootmysql5-7 mongodb-6.0.4]# cat start.sh #!/bin/bash…

js使用proxy代理监听控制事件

本文为proxy代理的实例应用&#xff0c;有关代理的内容可以参考&#xff1a; js语法---理解反射Reflect对象和代理Proxy对象 监听事件 要监听dom元素的事件&#xff0c;我们会采用回调触发的方式来执行操作&#xff0c; 而触发事件的过程很明显是一个异步操作&#xff0c;异…

Docker 使用基础(1)—镜像仓库

&#x1f3ac;慕斯主页&#xff1a;修仙—别有洞天 ♈️今日夜电波&#xff1a;秒針を噛む—ずっと真夜中でいいのに。 0:34━━━━━━️&#x1f49f;──────── 4:20 &#x1f504; ◀️ ⏸ …

android13 固定U盘链接 SD卡链接 TF卡链接 硬盘链接

1.前言 有些客户使用的应用并不带有自动监听U盘 sd卡广播的代码,使用的代码是固定的地址,这样的话,就需要我们将系统的挂载目录固定了。 原始路径 /storage/3123-19FA 增加链接 /storage/upan_000 -> /storage/3123-19FA 2. 首先如果是应用本身监听的话,使用的是 /…

【Linux线程篇】探索Linux多线程:并行编程的入门指南

W...Y的主页 &#x1f60a; 代码仓库分享&#x1f495; Linux线程概念 什么是线程 在一个程序里的一个执行路线就叫做线程&#xff08;thread&#xff09;。更准确的定义是&#xff1a;线程是“一个进程内部的控制序列”一切进程至少都有一个执行线程线程在进程内部运行&am…

揭秘:离心风机风量背后的科学原理

在工业生产和建筑环境中&#xff0c;离心风机如同一位不倦的呼吸管家&#xff0c;默默地维持着空气流动与品质。 你是否好奇过&#xff0c;究竟是什么因素在背后操纵着这位“呼吸管家”的风量表现呢&#xff1f;今天&#xff0c;就让我们一探究竟。 举个例子&#xff1a;你在吹…

『大模型笔记』GraphRAG:利用复杂信息进行发现的新方法!

GraphRAG:利用复杂信息进行发现的新方法! 文章目录 一. GraphRAG:利用复杂信息进行发现的新方法!1. 将RAG应用于私人数据集2. 整个数据集的推理3. 创建LLM生成的知识图谱4. 结果指标5. 下一步二. 参考文献微软官方推文:https://www.microsoft.com/en-us/research/blog/gra…

HTML5文本标签、图像标签、超链接

一、文本样式标签 字体样式标签&#xff1a; 加粗&#xff1a;<strong>…</strong> 斜体&#xff1a; < em >…</ em> eg&#xff1a; <h3>徐志摩人物简介</h3> <p> <strong>1910</strong>年入杭州学堂<br/> &l…

微信小程序 - 本地存储 增加有效期

小程序的本地存储API提供了wx.setStorageSync和wx.setStorage来存储数据&#xff0c;注意的是&#xff0c;小程序的本地存储并没有明确的有效期设置&#xff0c;存储的数据在不超过限制的情况下&#xff0c;会一直保留。 一、小程序本地存储API 小程序的本地存储API提供了设置…

WEB06JavaScriptAjax

基础语法 引入方式 引入方式 内部脚本&#xff1a;将JS代码定义在HTML页面中 JavaScript代码必须位于<script></script>标签之间 在HTML文档中&#xff0c;可以在任意地方&#xff0c;放置任意数量的<script> 一般会把脚本置于<body>元素的底部&a…