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

2024-03-22 22:20
文章标签 元素 力扣 ii 42 雨水 503 更大

本文主要是介绍力扣● 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]);rheight[i]=max(rheight[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、单调栈

如果按行装水的话,就可以通过下一个更大元素和上一个最大元素来求。

以上图为例,下标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==栈顶的话,要么不操作,要么替换这个栈顶,才能满足单调栈。这里需要选择的操作是替换栈顶,因为我们要求宽度的时候 如果遇到相同高度的柱子,需要使用最右边的柱子来计算宽度

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

清晰说明了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个pop()操作都有可能遇栈空,所以都要加条件,否则报错:

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;}
};

这篇关于力扣● 503.下一个更大元素II ● 42. 接雨水的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/836321

相关文章

在MyBatis的XML映射文件中<trim>元素所有场景下的完整使用示例代码

《在MyBatis的XML映射文件中<trim>元素所有场景下的完整使用示例代码》在MyBatis的XML映射文件中,trim元素用于动态添加SQL语句的一部分,处理前缀、后缀及多余的逗号或连接符,示... 在MyBATis的XML映射文件中,<trim>元素用于动态地添加SQL语句的一部分,例如SET或W

AI基础 L9 Local Search II 局部搜索

Local Beam search 对于当前的所有k个状态,生成它们的所有可能后继状态。 检查生成的后继状态中是否有任何状态是解决方案。 如果所有后继状态都不是解决方案,则从所有后继状态中选择k个最佳状态。 当达到预设的迭代次数或满足某个终止条件时,算法停止。 — Choose k successors randomly, biased towards good ones — Close

从0到1,AI我来了- (7)AI应用-ComfyUI-II(进阶)

上篇comfyUI 入门 ,了解了TA是个啥,这篇,我们通过ComfyUI 及其相关Lora 模型,生成一些更惊艳的图片。这篇主要了解这些内容:         1、哪里获取模型?         2、实践如何画一个美女?         3、附录:               1)相关SD(稳定扩散模型的组成部分)               2)模型放置目录(重要)

遮罩,在指定元素上进行遮罩

废话不多说,直接上代码: ps:依赖 jquer.js 1.首先,定义一个 Overlay.js  代码如下: /*遮罩 Overlay js 对象*/function Overlay(options){//{targetId:'',viewHtml:'',viewWidth:'',viewHeight:''}try{this.state=false;//遮罩状态 true 激活,f

学习记录:js算法(二十八):删除排序链表中的重复元素、删除排序链表中的重复元素II

文章目录 删除排序链表中的重复元素我的思路解法一:循环解法二:递归 网上思路 删除排序链表中的重复元素 II我的思路网上思路 总结 删除排序链表中的重复元素 给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。 图一 图二 示例 1:(图一)输入:head = [1,1,2]输出:[1,2]示例 2:(图

两数之和--力扣1

两数之和 题目思路C++代码 题目 思路 根据题目要求,元素不能重复且不需要排序,我们这里使用哈希表unordered_map。注意题目说了只对应一种答案。 所以我们在循环中,使用目标值减去当前循环的nums[i],得到差值,如果我们在map中能够找到这个差值,就说明存在两个整数的和为目标值。 如果没有找到,就将当前循环的nums[i]以及下标i放入map中,以便后续查

JS和jQuery获取节点的兄弟,父级,子级元素

原文转自http://blog.csdn.net/duanshuyong/article/details/7562423 先说一下JS的获取方法,其要比JQUERY的方法麻烦很多,后面以JQUERY的方法作对比。 JS的方法会比JQUERY麻烦很多,主要则是因为FF浏览器,FF浏览器会把你的换行也当最DOM元素。 <div id="test"><div></div><div></div

力扣第347题 前K个高频元素

前言 记录一下刷题历程 力扣第347题 前K个高频元素 前K个高频元素 原题目: 分析 我们首先使用哈希表来统计数字出现的频率,然后我们使用一个桶排序。我们首先定义一个长度为n+1的数组,对于下图这个示例就是长度为7的数组。为什么需要一个长度为n+1的数组呢?假如说总共有三个数字都为1,那么我们需要把这个1放在数组下标为3的位置,假如说数组长度为n,对于这个例子就是长度为3,那么它的

QML入门之基本元素

元素分为可视元素与非可视元素,可能元素例如Rectangle、Button等。非可视元素如Timer(定时器)、MouseArea(鼠标区域)等。非可视元素一般用于操作可视元素。 基础元素 Item Item(基础元素对象)是所有可视元素的基础对象,它们都继承自Item。可是元素存在以下共有属性。 Group(分组)Properties(属性)Geometry(几何属性)x

【CSS in Depth 2 精译_024】4.2 弹性子元素的大小

当前内容所在位置(可进入专栏查看其他译好的章节内容) 第一章 层叠、优先级与继承(已完结) 1.1 层叠1.2 继承1.3 特殊值1.4 简写属性1.5 CSS 渐进式增强技术1.6 本章小结 第二章 相对单位(已完结) 2.1 相对单位的威力2.2 em 与 rem2.3 告别像素思维2.4 视口的相对单位2.5 无单位的数值与行高2.6 自定义属性2.7 本章小结 第三章 文档流与盒模型(已