力扣● 503.下一个更大元素II ● 42. 接雨水

  •  503.下一个更大元素II 

与496.下一个更大元素 I的不同是要循环地搜索元素的下一个更大的数。那么主要是对于遍历结束后,单调栈里面剩下的那些元素。

如果直接把两个数组拼接在一起,然后使用单调栈求下一个最大值就可以。

代码实现的话,不用直接把数组后面再接一个数组,而是单调栈走2遍这个数组即可。

代码如下。第二次遍历使用取余的方法。
 

class Solution {
public:vector<int> nextGreaterElements(vector<int>& nums) {int n=nums.size();vector<int> result(n,-1);stack<int> st;for(int i=0;i<2*n;++i){int k=i%n;while(!st.empty() && nums[k]>nums[st.top()]){result[st.top()]=nums[k];st.pop();}st.push(k);}return result;}
};

  •  42. 接雨水  

依据列来计算更好理解,能引入单调栈:可以看出,因为左侧最高柱子和右侧最高柱子肯定不会存储雨水(左侧和右侧包含自己,因为自己是一侧最高的话不会存储雨水),所以每一列雨水的高度,取决于,该列 左侧最高的柱子和右侧最高的柱子中最矮的那个柱子的高度。

下面图片以柱子4为例,可以看见中间所有柱子都满足这个结论,最两边的柱子不会存储雨水。

转化问题后,有3种办法解决:

  • 会超时的暴力解法。
  • 双指针优化。
  • 重点的单调栈。

1、暴力解法。

对于每个元素,都从左、从右找最大高度的柱子lheight、rheight,所以外层循环是0到n-1,内层循环从i往左,然后从i往右找最大高度的柱子lheight、rheight,最多会查找n次。所以时间复杂度是O(n^2),空间复杂度O(1)。但是会超时。

2、双指针优化。

当前元素的左边、右边最大高度的柱子lheight、rheight其实跟前一个元素的lheight、rheight有关。注意左边最大和右边最大要把自己考虑进去,如果不包含,左边最大/右边最大的可能比自己还小,那么相减是负数,最终结果比正确结果小。

当前i的lheight取决于左边i-1的lheight,rheight取决于右边i+1的rheight。具体如下:

当前i的lheight=max(前一个lheight,height[i]),所以需要从左到右得到lheight。

那么参照lheight,当前i的rheight应该=max(后一个lheight,height[i]),与上面相反,从右到左得到。

根据这个过程先把所有元素的lheight数组和rheight数组求出来,然后再遍历元素的时候,直接就是min(lheight[i],rheight[i])-height[i]。时间复杂度是O(n),空间复杂度O(n)。

代码如下。

class Solution {
public:int trap(vector<int>& height) {int n=height.size();int l1,r1,l2,r2;int count=0;vector<int> lheight(n);vector<int> rheight(n);//初始化lheight[0]=height[0];rheight[n-1]=height[n-1];for(int i=1;i<n-1;++i){//中间元素的lheight和rheightlheight[i]=max(lheight[i-1],height[i]);}for(int i=n-2;i>0;--i){rheight[i]=max(rheight[i+1],height[i]);}//挨个计算for(int i=0;i<n;++i){if(i==0 || i==n-1)continue;int cur=min(lheight[i],rheight[i])-height[i];count+=cur;}return count;}
};

上面的1、2都是按照列的方式去装水,因为是找左右两边最大元素。

3、单调栈

如果按行装水的话,就可以通过下一个更大元素leftmax和上一个更大元素rightmax来求。上一个更大和下一个更大之间,都是比i自己小的元素,所以中间这些柱子都可以存储一行的水,这一行的底是height[i],高是min(height[leftmax],height[rightmax])。左边起始位置是leftmax+1,右边结束位置是 rightmax-1。

以上图为例,下标2左边更大是1,右边更大是2,自己这行(以下标2柱高0为底,以min(左边更大值,右边更大值)为高,宽度是2个更大值的距离1)可以存储1的雨水;下标4左边更大是2,右边更大是3,所以自己这行(以下标4柱高1为底,以min(左边更大值,右边更大值)=2为高,宽度是2个更大值的距离3)可以存储3的雨水……左边更大和右边更大有1个不存在的则存储雨水为0。

所以要用单调栈计算出上一个更大值和下一个更大值的下标leftmax和rightmax。然后i柱子处可以存储的雨水是:(min(height[leftmax],height[rightmax])-height[i])*(rightmax-leftmax-1)。

怎么计算上一个更大值和下一个更大值呢?还想着2次单调栈,实际上,1次单调栈即可。采用单调递增栈,在元素 i 比栈顶大的情况下,如果栈顶同时也比次栈顶要小,这个时候就出现一个凹槽,也就找到了上一个更大值(次栈顶)和下一个更大值(元素i)。所以这个单调递增栈,必须是严格的单增,这个凹槽一定是次栈顶>栈顶<比栈顶大的元素i。

所以如果元素i==栈顶的话,要么不操作,要么替换这个栈顶,才能满足单调栈。这里其实2个都可以,我们只用到了栈顶元素的值height[mid],而没有直接操作他的下标,所以==的时候单独写和不写都行。

如果<栈顶,就直接入栈。

清晰说明了3种情况:

class Solution {
public:int trap(vector<int>& height) {int n=height.size();int count=0;stack<int> st;st.push(0);for(int i=1;i<n;++i){if(height[i]==height[st.top()]){st.pop();st.push(i);}else if(height[i]<height[st.top()])st.push(i);else{while(!st.empty()&&height[i]>height[st.top()]){//有凹槽,top是中间int mid=st.top();st.pop();if(!st.empty()){//取栈顶,都要判断非空int h=min(height[i],height[st.top()])-height[mid];//高int w=i-st.top()-1;//宽count+=w*h;}}st.push(i);}}return count;}
};

相等的情况pop()之前应该检查是否为空,但是初始和每一次循环结尾都有入栈操作,所以这里不用加。

简化。简化后的3个top()操作都有可能遇栈空,所以都要加判空条件,否则报错:

class Solution {
public:int trap(vector<int>& height) {int n=height.size();int count=0;stack<int> st;st.push(0);for(int i=1;i<n;++i){while(!st.empty()&&height[i]>height[st.top()]){//有凹槽,top是中间int mid=st.top();st.pop();if(!st.empty()){//取栈顶,都要判断非空int h=min(height[i],height[st.top()])-height[mid];//高int w=i-st.top()-1;//宽count+=w*h;}}if(!st.empty()&&height[i]==height[st.top()]){//可加可不加st.pop();}st.push(i);}return count;}
};

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

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

相关文章

RHCE-3-远程登录服务

简介 概念 远程连接服务器通过文字或图形接口方式来远程登录系统&#xff0c;让你在远程终端前登录linux主机以取得可操作主机接口&#xff08;shell&#xff09;&#xff0c;而登录后的操作感觉就像是坐在系统前面一样 功能: 分享主机的运算能力 服务器类型&#xff1a;有限…

hcia datacom课程学习(4):ICMP与ping命令

1.什么是ICMP ICMP是ip协议的一部分&#xff0c;常用的ping命令就是基于icmp协议的。 在防火墙策略中也能看到ICMP&#xff0c;如果将其禁用&#xff0c;那么其他主机就ping不通该主机了 2. ICMP数据报 2.1数据报构成 ICMP协议的报文包含在IP数据报的数据部分&#xff0c; …

from_pretrained 做了啥

transformers的三个核心抽象类是Config, Tokenizer和Model&#xff0c;这些类根据模型种类的不同&#xff0c;派生出一系列的子类。构造这些派生类的对象也很简单&#xff0c;transformers为这三个类都提供了自动类型&#xff0c;即AutoConfig, AutoTokenizer和AutoModel。三个…

力扣 718. 最长重复子数组

题目来源&#xff1a;https://leetcode.cn/problems/maximum-length-of-repeated-subarray/description/ C题解&#xff08;思路来源代码随想录&#xff09;&#xff1a;动态规划 确定dp数组&#xff08;dp table&#xff09;以及下标的含义。dp[i][j] &#xff1a;以下标i - …

【数据结构与算法】判断字符串是否括号匹配

题目 一个字符串 s 可能包含 { } ( ) [ ] 三种括号判断 s 是否是括号匹配的如(a{b}c) 匹配&#xff0c;而 {a(b 或 {a(b}c) 不匹配 栈 先进后出API&#xff1a; push pop length相关的&#xff1a;队列、堆 栈和数组的关系或区别 栈是一种逻辑结构&#xff0c;理论模型&am…

c语言编译和链接

一个.c源文件是如何经过处理变成可执行的.exe文件&#xff1f; 这其中经过了编译和链接两个大过程。总的来讲&#xff0c;就是每个源文件经过编译后生成对应地目标文件&#xff0c;然后所有的目标文件和所引用的标准库链接&#xff0c;形成了.exe文件。具体是怎样&#xff0c;…

TTS 文本转语音模型综合简述

本文参考文献&#xff1a; [1] Kaur N, Singh P. Conventional and contemporary approaches used in text ot speech synthesis: A review[J]. Artificial Intelligence Review, 2023, 56(7): 5837-5880. [2] TTS | 一文了解语音合成经典论文/最新语音合成论文篇【20240111更新…

代码随想录算法训练营第二十二天|235.二叉搜索树的最近公共祖先、701.二叉搜索树中的插入操作、450.删除二叉搜索树中的节点

代码随想录算法训练营第二十二天|235.二叉搜索树的最近公共祖先、701.二叉搜索树中的插入操作、450.删除二叉搜索树中的节点 35.二叉搜索树的最近公共祖先 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有…

2024 ccfcsp认证打卡 2023 03 01 田地丈量

import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner in new Scanner(System.in);int n in.nextInt(); // 输入 n&#xff0c;表示矩形的数量int a in.nextInt(); // 输入 a&#xff0c;表示整个区域的长度int b in.nextInt()…

Git 常用命令速查

Git 是一个分布式版本控制系统&#xff0c;用于管理代码和其他文件。它允许您跟踪代码的更改&#xff0c;并在必要时回滚到以前的版本。 本文将介绍一些 Git 常用命令&#xff0c;帮助您快速上手 Git。 初始化 Git 仓库 git init添加文件到暂存区 git add <file_name>…

superset 二开增加 flink 数据源连接通过flink sql 查询数据

前言 superset 目前还不支持 flink 的数据源连接&#xff0c;目前我们公司在探索使用数据湖那一套东西&#xff1a; 使用 flink 作为计算引擎使用 paimon oss对象存储对接 flink 作为底层存储使用 superset 通过 flink gateway 查询 paimon 数据形成报表 增加flink数据源 …

C++零基础入门学习视频课程

教程介绍 本专题主要讲解C基础入门学习&#xff0c;所以不会涉及很深入的语法和机制。但会让你整体多面的了解和学习C的核心内容&#xff0c;快速学习使用C&#xff0c;我们的目标是先宏观整体把握&#xff0c;在深入各个击破&#xff01; 学习地址 链接&#xff1a;https:/…

简单谈谈什么是块存储?

块存储是最简单的数据存储形式&#xff0c;通常用于存储区域网络(SAN) 或 云存储 设置。文件存储在固定大小的块中&#xff0c;可以更轻松地访问文件以进行快速或频繁的编辑。虽然更复杂且成本更高&#xff0c;但存储在此类系统中的数据可以轻松访问&#xff0c;而不会影响操作…

如何在Win10使用IIS服务搭建WebDAV网站并实现无公网IP访问内网文件内容

文章目录 前言1. 安装IIS必要WebDav组件2. 客户端测试3. 使用cpolar内网穿透&#xff0c;将WebDav服务暴露在公网3.1 安装cpolar内网穿透3.2 配置WebDav公网访问地址 4. 映射本地盘符访问 前言 在Windows上如何搭建WebDav&#xff0c;并且结合cpolar的内网穿透工具实现在公网访…

docker 的八大技术架构(图解)

docker 的八大技术架构 单机架构 概念&#xff1a; 应用服务和数据库服务公用一台服务器 出现背景&#xff1a; 出现在互联网早期&#xff0c;访问量比较小&#xff0c;单机足以满足需求 架构优缺点&#xff1a; 优点&#xff1a;部署简单&#xff0c;成本低 缺点&#xff1…

80个Python数据分析必备实战案例.pdf(附代码),完全开放下载

大家好&#xff0c;我是彭涛。 随着数据时代的来临&#xff0c;Python数据分析技能现在愈加重要&#xff0c;无论是从事数据科学、商业分析还是决策支持&#xff0c;掌握 Python 数据分析的技能都将成为你事半功倍的利器。 之前为大家陆续梳理了基础资料&#xff0c;爬虫资料…

C# WPF编程-事件

C# WPF编程-路由事件 路由事件概要路由事件的三种方式 WPF事件WPF最重要的5类事件&#xff1a;生命周期事件 鼠标事件键盘事件多点触控输入原始触控 路由事件概要 路由事件是具有更强传播能力的事件&#xff0c;它们可在元素树中向上冒泡和向下隧道传播&#xff0c;并沿着传播…

网易web安全工程师进阶版课程

课程介绍 《Web安全工程师&#xff08;进阶&#xff09;》是由“ i春秋学院联合网易安全部”出品&#xff0c;资深讲师团队通过精炼的教学内容、丰富的实际场景及综合项目实战&#xff0c;帮助学员纵向提升技能&#xff0c;横向拓宽视野&#xff0c;牢靠掌握Web安全工程师核心…

【任职资格】某大型制造型企业任职资格体系项目纪实

该企业以业绩、责任、能力为导向&#xff0c;确定了分层分类的整体薪酬模式&#xff0c;但是每一名员工到底应该拿多少工资&#xff0c;同一个岗位的人员是否应该拿同样的工资是管理人员比较头疼的事情。华恒智信顾问认为&#xff0c;通过任职资格评价能实现真正的人岗匹配&…

DVB-S系统仿真学习

DVB-S系统用于卫星电视信号传输&#xff0c;发送端框图如下所示 扰码 实际数字通信中&#xff0c;载荷数据的码元会出现长连0或长连1的情况&#xff0c;不利于接收端提取时钟信号&#xff0c;同时会使得数据流中含有大量的低频分量&#xff0c;使得QPSK调制器的相位长时间不变…