单调栈学习C++

目录

一,每日温度

二,下一个更大的元素I

三,下一个更大的元素II

四,接雨水

小结:


 单调栈是一种特殊的栈结构,里面的元素按照单调递增或者递减的顺序排列。常用于解决元素左边或者右边比它大或者小的问题。

一,每日温度

题目链接:739. 每日温度 - 力扣(LeetCode)

【题目描述】

 对于给定的一个temperatures数组,每个元素表示当天的温度。对于每天的温度,求出下一次更高的温度出现在几天后。

【算法】单调栈

我们可以维护一个栈结构,先将数组的首元素入栈,然后开始遍历这个数组,如果遍历到的数组元素比栈顶元素小,那么就入栈;如果相等,也入栈;当遍历到的数组元素比此时栈顶的元素大时,记录此时相隔的天数,然后将栈顶元素弹出,继续比较栈顶的元素和数组元素的大小,直到栈顶元素小于或者等于栈顶元素,此时将该数组元素入栈。然后接着遍历下一个数组元素,依次循环。

由于题目中求的是相隔的天数,所以我们不需要将数组元素入栈,只需入栈该元素的下标即可,这样就可以直接计算相隔的天数:数组元素对应的下标减去栈顶元素对应的下标,就是该栈顶元素与下一个更高温度相隔的天数。 

图示:(以题目中的示例1为例)

可以发现,栈中的元素(下标对应的元素)始终保持单调递减(从栈底到栈顶),因此成为单调栈。 

【代码】

class Solution {
public:vector<int> dailyTemperatures(vector<int>& temperatures) {int n=temperatures.size();vector<int> ans(n,0);stack<int> st;//存储下标st.push(0);for(int i=1;i<n;i++){//遇到温度大于栈顶的,就一直出栈,保持递减性while(!st.empty()&&temperatures[st.top()]<temperatures[i]){int index=st.top();st.pop();ans[index]=i-index;}st.push(i);}return ans;}
};

时间复杂度O(N),每个元素最多入栈依次。空间复杂度O(N) 

二,下一个更大的元素I

题目链接:496. 下一个更大元素 I - 力扣(LeetCode)

【题目描述】

本题存在两个数组,nums1是nums2的子集,对于nums1数组的每个元素,求出这些元素在对应nums2数组中的下一个更大的元素。如果不存在,则为-1

【算法】单调栈

本题与上一题的思路一样,只不过加了一点要求。

求当前元素的下一个更大的元素,就需要维护一个单调栈(单调递减)。

本题还是求数组nums2上每个元素的下一个更大的元素是多少。所以还是在nums2数组上使用单调栈。和上题的过程一样,只不过在判断的时候,还需加上一个条件。

假设找到了当前栈顶的下一个更大元素k,还需判断栈顶元素是否在nums1中出现过,如果该元素在nums1中出现过,那么就将k记录在最终结果数组ans中,不过还需要保证和nums1数组的位置一一对应。

所以可以做下预处理工作,将数组nums1中的元素和下标使用哈希表保存起来。

初始化ans数组时,可以全部初始化为-1.

【代码】

class Solution {
public:vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {int n=nums1.size();vector<int> ans(n,-1);unordered_map<int,int> hash;for(int i=0;i<n;i++)hash[nums1[i]]=i;stack<int> st;//单调递减st.push(0);for(int i=1;i<nums2.size();i++){while(!st.empty()&&nums2[st.top()]<nums2[i]){//判断是否在nums1中出现过if(hash.count(nums2[st.top()])>0){//求出该元素在nums1中对应的下标int index=hash[nums2[st.top()]];//记录结果ans[index]=nums2[i];}st.pop();}st.push(i);}return ans;}
};

三,下一个更大的元素II

题目链接:503. 下一个更大元素 II - 力扣(LeetCode)

【题目描述】

 求一个数组nums每一个元素的下一个更大的数,该数组是循环数组,数组最后一个元素接下来的元素就是数组的第一个元素。

【算法】单调栈

求下一个更大的元素,单调栈(单调递减栈)。

大致的方向还是使用单调栈。本题的重点是:如何处理循环数组。

方法一:是将原数组nums在后面再拼接一份。然后使用单调栈求下一个更大的元素。

将两个nums数组拼接起来,使用单调栈求出每一个元素的下一个更大值,存储在ans数组中,然后将ans数组的大小减为一半。

class Solution {
public:vector<int> nextGreaterElements(vector<int>& nums) {//拼接两个数组vector<int> nums1(nums.begin(),nums.end());nums.insert(nums.begin(),nums1.begin(),nums1.end());vector<int> ans(nums.size(),-1);stack<int> st;//单调递减st.push(0);for(int i=1;i<nums.size();i++){while(!st.empty()&&nums[st.top()]<nums[i]){ans[st.top()]=nums[i];st.pop();}st.push(i);}//将数组减为原来的一般ans.resize(nums.size()/2);return ans;}
};

方法二:也可以不用扩充数组,在遍历的时候模拟走两边nums即可。

class Solution {
public:vector<int> nextGreaterElements(vector<int>& nums) {int n=nums.size();vector<int> ans(n,-1);stack<int> st;//单调递减st.push(0);//模拟走两边nums//当遍历完最后一个元素,执行++后,再取模n,会回到数组的开始for(int i=1;i<2*n;i++){while(!st.empty()&&nums[st.top()]<nums[i%n]){ans[st.top()]=nums[i%n];st.pop();}st.push(i%n);}return ans;}
};

四,接雨水

题目链接:42. 接雨水 - 力扣(LeetCode)

【解法一】双指针 

求这些柱子中一共有多少雨水。看每个柱子可以"接"多少雨水。

也就是统计每个柱子上有多少水,然后将每个柱子上的水加起来即可。

问题是如何求每个柱子上有多少水?

对于第i个柱子,求第i个柱子上有多少水,需要求出第i个柱子左边柱子最高的高度,以及第i个柱子右边柱子最高的高度,取两者的最小值,然后再减去当前柱子的高度。

【代码】

class Solution {
public:int trap(vector<int>& height) {//双指针int n=height.size();vector<int> maxLeft(n,0);auto maxRight=maxLeft;//记录左边最大值maxLeft[0]=height[0];for(int i=1;i<n;i++)maxLeft[i]=max(maxLeft[i-1],height[i]);//记录右边最大值maxRight[n-1]=height[n-1];for(int i=n-2;i>=0;i--)maxRight[i]=max(maxRight[i+1],height[i]);int ans=0;for(int i=0;i<n;i++){int count=min(maxLeft[i],maxRight[i])-height[i];if(count>0) ans+=count;}return ans;}
};

【解法二】单调队列

这种思路是求柱子与柱子之间的雨水量。

首先需要明白,当后一个柱子高度大于前一个柱子高度,那么一定是会有雨水的。

所以我们需要求下一个更大的元素,使用单调递减栈。

思路,与前面题的思路一致。


当遍历到的元素大于栈顶元素时:

此时的栈顶就是下图的中间柱子,下标记为mid,对应的高度为height[mid],将栈顶元素弹出。

此时的栈顶元素st.top(),就是最左边的柱子,对应的高度为height[st.top()]。

此时遍历到的元素是最右边的柱子,下标为i,柱子高度为height[i]。

最后只需计算出中间雨水的长和宽然后相乘即可。

h=min(height[st.top()],height[i])-height[mid]

w=i-st.top()-1

【代码】

class Solution {
public:int trap(vector<int>& height) {int n=height.size();int ans=0;stack<int> st;//单调递减st.push(0);for(int i=1;i<n;i++){while(!st.empty()&&height[st.top()]<height[i]){int mid=st.top();st.pop();if(!st.empty()){int h=min(height[st.top()],height[i])-height[mid];int w=i-st.top()-1;ans+=h*w;}}st.push(i);}return ans;}
};

小结:

单调栈常用于解决元素左侧或者右侧第一个更大后者更小的问题。

核心原理:

  • 单调递增栈:栈内元素从栈底到栈顶递增,用于寻找更小的元素。

  • 单调递减栈:栈内元素从栈底到栈顶递减,用于寻找更大的元素。

  • 遍历数组时,若当前元素破坏单调性,则弹出栈顶元素,直到满足单调性。

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

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

相关文章

网络钓鱼攻击的威胁和执法部门的作用(第一部分)

在当今的数字世界中&#xff0c;网络犯罪分子不断开发新技术来利用个人、企业和政府机构。 最普遍和最具破坏性的网络犯罪形式之一是网络钓鱼——一种社会工程手段&#xff0c;用于欺骗人们提供敏感信息&#xff0c;例如登录凭据、财务数据和个人详细信息。 随着网络钓鱼攻击…

左值与右值,空间与数据

左值是空间&#xff0c;右值是数据 编程总是对“数据”&#xff0c;对"存放数据的空间"操作 a返回一个当前的数据&#xff0c;存放到一个临时空间中&#xff0c;自身的空间中的数据再进行运算 a直接对自身空间中的数据进行运算 其余知识&#xff1a; 1.变量名的意…

无人机飞行术语科普!

一、基础操作类 1. 炸机 指无人机意外坠毁或严重损坏&#xff08;如撞树、撞楼、失控摔机等&#xff09;。 例句&#xff1a;“今天风太大&#xff0c;差点炸机&#xff01;” 2. 一键放生 调侃某些情况下无人机失控飞丢&#xff0c;无法找回&#xff08;源自某些品牌…

模拟算法(一):一维数组模拟

目录 模拟的概念 例1&#xff1a;开关灯 算法思路&#xff1a; 代码如下&#xff1a; 输入输出&#xff1a; 例2&#xff1a;序列操作和查询 算法思路&#xff1a; 代码如下&#xff1a; 输入输出&#xff1a; 例3&#xff1a;数组折叠 算法思路&#xff1a; 代码如…

MySQL 基础入门

写在前面 关于MySQL的下载安装和其图形化软件Navicat的下载安装,网上已经有了很多的教程,这里就不再赘述了,本文主要是介绍了关于MySQL数据库的基础知识。 MySQL数据库 MySQL数据库基础 MySQL数据库概念 MySQL 数据库&#xff1a; 是一个关系型数据库管理系统 。 支持SQL语…

Qt中的多种输出方式,信号与槽的基本使用

完成Hello World可以通过很多控件实现 如采用编辑框来完成hello world 编辑框分为单行编辑框----QLineEdit 和多行编辑框---QTextEdit 采用单行编辑框&#xff0c;创建项目后&#xff0c;展开forms文件夹&#xff0c;双击ui文件进入 qt designer设计页面 找到line edit 拖到页…

英语表达年代和世纪

英语表达年代和世纪 1. Century (世纪)1.1. Start and end of centuries 2. Decade (年代)2.1. Usage 3. 英语表达年代和世纪4. HomeworkReferences XXX0 年代指 XXX0 年 - XXX9 年的连续 10 年&#xff0c;例如 1760 年代指 1760 年至 1769 年这连续 10 年。 XX 世纪 X0 年代…

MySQL数据库管理5

23.事务 1&#xff09;事务&#xff1a;可以认为是做一件事情 需要多个SQL 要么同时成功 要么同时失败 需求&#xff1a;银行转账update 你的账户 把你的钱减少update 你朋友的账户 把他的钱增多​这两个SQL不能只成功一个 要么都成功 要么都失败那么 我们就需要用到事务了 它…

闭包和装饰器

什么是闭包 闭包&#xff08;Closure&#xff09;是 Python 中一个非常重要的概念&#xff0c;它是一种特殊的函数对象&#xff0c;通常用于封装和延迟计算某些值。以下是闭包的详细定义和解释&#xff1a; 1.闭包的定义 闭包是指一个函数对象&#xff0c;它不仅包含函数的代…

notepad++8.6.4安装及细节

notepad8.6.4下载安装&#xff08;附安装包&#xff09; 一、安装包下载1.1方法一&#xff1a;官网下载&#xff08;点击跳转&#xff09;1.2方法二&#xff1a;网盘链接分享8.6.4版本 二、安装过程细节2.1这里的组件建议全部勾选。点击“下一步”。2.2 勾选①&#xff1a;可以…

COZE通关指南:工作流与插件开发

前言 本文隶属于专栏《AI Agent 通关指南》,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢! 本专栏目录结构和参考文献请见《AI Agent 通关指南》 正文 1. 平台基础介绍 🌟 1.1 COZE平台概述 COZE平台(coze.cn)是一个强大的AI应用开发平台…

【Block总结】ENLTransformerBlock,高效非局部变换器块|即插即用

1. 论文信息 标题: Perspective+ Unet: Enhancing Segmentation with Bi-Path Fusion and Efficient Non-Local Attention for Superior Receptive Fields论文地址: arXiv:2406.14052 2. 创新点 双路径编码策略: 在编码器阶段引入双路径策略,结合传统卷积和空洞卷积的结果,平…

【爬虫】网易云音乐评论数据爬取

文章目录 &#x1f356; 前言&#x1f3b6;一、抓取要求✨二、代码展示&#x1f3c0;三、运行结果&#x1f3c6;四、知识点提示 &#x1f356; 前言 【爬虫】网易云音乐歌词/评论数据爬取 &#x1f3b6;一、抓取要求 描述: 输入歌曲的id&#xff0c;获取对应歌曲的用户评论信…

C++使用Qt Charts创建数据可视化图表

Qt Charts 是一个强大的工具&#xff0c;用于创建直观的数据可视化图表。本文将通过一个具体的示例&#xff0c;展示如何使用 Qt Charts 创建一个包含多条数据序列、自定义坐标轴和随机数据生成的图表。 示例代码解析 以下是一个完整的示例代码&#xff0c;展示如何使用 Qt Ch…

TCP/IP五层协议

目录 1. 五层模型结构 2. 各层核心功能与协议 (1) 应用层&#xff08;Application Layer&#xff09; (2) 传输层&#xff08;Transport Layer&#xff09; (3) 网络层&#xff08;Network Layer&#xff09; (4) 数据链路层&#xff08;Data Link Layer&#xff09; (5…

【最新版】金媒婚恋系统v10.5最新稳定开源+原生前端小程序 PC端+安装教程

一.系统简介 1. 红娘服务 红娘服务模块是该系统的一大特色。专业红娘会通过分析用户的个人资料和偏好&#xff0c; 为用户提供精准的配对建议和个性化服务。用户可以预约红娘服务&#xff0c;通过红娘的介入&#xff0c;提升配对成功率。 2. 相亲活动 相亲活动模块用于组织和管…

吴恩达深度学习复盘(5)神经网络的前向传播TesorFlow与NumPy实现比对

数据结构差别 NumPy 和 TensorFlow 在数据表示上的差异展开&#xff0c;结合神经网络实践中的常见问题进行说明。以下是详细解析&#xff1a; 一、简介 数据表示的历史背景 NumPy 是 Python 科学计算的基础库&#xff0c;早期设计为处理多维数组TensorFlow 由 Google Brain 团…

多元高斯分布函数

1、 n n n元向量 假设 n n n元随机变量 X X X X [ X 1 , X 2 , ⋯ , X i , ⋯ , X n ] T μ [ μ 1 , μ 2 , ⋯ , μ i , ⋯ , μ n ] T σ [ σ 1 , σ 2 , ⋯ , σ i , ⋯ , σ n ] T X i ∼ N ( μ i , σ i 2 ) \begin{split} X&[X_1,X_2,\cdots,X_i,\cdots ,X_n…

洞察 Linux 进程管理

一、进程和线程的概念 1.进程 &#xff08;1&#xff09;概念 进程是程序在操作系统中的一次执行过程&#xff0c;是系统进行资源分配和调度的基本单位。进程是程序的执行实例&#xff0c;拥有独立的资源&#xff08;如内存、文件描述符等&#xff09;。每个进程在创建时会被…

PyTorch 实现图像版多头注意力(Multi-Head Attention)和自注意力(Self-Attention)

本文提供一个适用于图像输入的多头注意力机制&#xff08;Multi-Head Attention&#xff09;PyTorch 实现&#xff0c;适用于 ViT、MAE 等视觉 Transformer 中的注意力计算。 模块说明 输入支持图像格式 (B, C, H, W)内部转换为序列 (B, N, C)&#xff0c;其中 N H * W多头注…