DAY53|| 42. 接雨水|84.柱状图中最大的矩形

42. 接雨水(超经典款)

42. 接雨水 - 力扣(LeetCode)

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

示例 1:

输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 

示例 2:

输入:height = [4,2,0,3,2,5]
输出:9

双指针法(优先掌握)

在暴力解法中,我们可以看到只要记录左边柱子的最高高度 和 右边柱子的最高高度,就可以计算当前位置的雨水面积,这就是通过列来计算。

当前列雨水面积:min(左边柱子的最高高度,记录右边柱子的最高高度) - 当前柱子高度。

当前位置,左边的最高高度是前一个位置的左边最高高度和本高度的最大值。

即从左向右遍历:maxLeft[i] = max(height[i], maxLeft[i - 1]);

从右向左遍历:maxRight[i] = max(height[i], maxRight[i + 1]);

class Solution {
public:
//双指针法int trap(vector<int>& height) {if(height.size()<=2)return 0;vector<int>maxleft(height.size(),0);vector<int>maxright(height.size(),0);int size=height.size();//记录每个柱子左边柱子的最大值maxleft[0]=height[0];for(int i=1;i<size;i++){maxleft[i]=max(height[i],maxleft[i-1]);}//记录每个柱子右边柱子的最大值maxright[size-1]=height[size-1];for(int i=size-2;i>=0;i--)maxright[i]=max(maxright[i+1],height[i]);//求所有雨水的面积和int sum=0;for(int i=0;i<size;i++){int count=min(maxleft[i],maxright[i])-height[i];if(count>0)sum+=count;}return sum;}
};

单调栈

单调栈就是保持栈内元素有序。和栈与队列:单调队列 (opens new window)一样,需要我们自己维持顺序,没有现成的容器可以用。

通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,此时我们就要想到可以用单调栈了。

而接雨水这道题目,我们正需要寻找一个元素,右边最大元素以及左边最大元素,来计算雨水面积。

首先,

其次,从栈顶到栈底是从小到大,因为求的是右边第一个比当前元素大的元素。 

我们要求宽度的时候 如果遇到相同高度的柱子,需要使用最右边的柱子来计算宽度

如图所示:

42.接雨水5

  1. 栈里要保存什么数值

栈里就存放下标就行,想要知道对应的高度,通过height[stack.top()] 就知道弹出的下标对应的高度了。

单调栈处理逻辑 

  • 情况一:当前遍历的元素(柱子)高度小于栈顶元素的高度 height[i] < height[st.top()]
  • 情况二:当前遍历的元素(柱子)高度等于栈顶元素的高度 height[i] == height[st.top()]
  • 情况三:当前遍历的元素(柱子)高度大于栈顶元素的高度 height[i] > height[st.top()]

如果当前遍历的元素(柱子)高度大于栈顶元素的高度,此时就出现凹槽了,如图所示:

42.接雨水4

栈顶元素弹出,凹槽的底部,也就是中间位置,下标记为mid,对应的高度为height[mid](图中的高度1)。

栈顶元素st.top(),就是凹槽的左边位置,下标为st.top(),对应的高度为height[st.top()](图中的高度2)。

当前遍历的元素i,就是凹槽右边的位置,下标为i,对应的高度为height[i](就是图中的高度3)。

其实就是栈顶和栈顶的下一个元素以及要入栈的元素,三个元素来接水!

那么雨水高度是 min(凹槽左边高度, 凹槽右边高度) - 凹槽底部高度,代码为:int h = min(height[st.top()], height[i]) - height[mid];

雨水的宽度是 凹槽右边的下标 - 凹槽左边的下标 - 1(因为只求中间宽度),代码为:int w = i - st.top() - 1 ;

当前凹槽雨水的体积就是:h * w

代码 

class Solution {
public:
//单调栈法int trap(vector<int>& height) {if(height.size()<=2)return 0;stack<int>st;//只记录元素下标st.push(0);int sum=0;for(int i=1;i<height.size();i++){if(height[i]<=height[st.top()])//情况一和二st.push(i);else{while(!st.empty()&&height[i]>height[st.top()]){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;//求宽带sum+=h*w;}}st.push(i);//怎么老是忘记这一个,要记得加入新的元素下标啊啊}}return sum;}
};

84.柱状图中最大的矩形

84. 柱状图中最大的矩形 - 力扣(LeetCode)

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。

求在该柱状图中,能够勾勒出来的矩形的最大面积。

示例 1:

输入:heights = [2,1,5,6,2,3]
输出:10
解释:最大的矩形为图中红色区域,面积为 10

示例 2:

输入: heights = [2,4]
输出: 4

双指针法(难理解)

class Solution {
public:int largestRectangleArea(vector<int>& heights) {vector<int> minLeftIndex(heights.size());vector<int> minRightIndex(heights.size());int size = heights.size();// 记录每个柱子 左边第一个小于该柱子的下标minLeftIndex[0] = -1; // 注意这里初始化,防止下面while死循环for (int i = 1; i < size; i++) {int t = i - 1;// 这里不是用if,而是不断向左寻找的过程while (t >= 0 && heights[t] >= heights[i]) t = minLeftIndex[t];minLeftIndex[i] = t;}// 记录每个柱子 右边第一个小于该柱子的下标minRightIndex[size - 1] = size; // 注意这里初始化,防止下面while死循环for (int i = size - 2; i >= 0; i--) {int t = i + 1;// 这里不是用if,而是不断向右寻找的过程while (t < size && heights[t] >= heights[i]) t = minRightIndex[t];minRightIndex[i] = t;}// 求和int result = 0;for (int i = 0; i < size; i++) {int sum = heights[i] * (minRightIndex[i] - minLeftIndex[i] - 1);result = max(sum, result);}return result;}
};

单调栈法

因为本题是要找每个柱子左右两边第一个小于该柱子的柱子,所以从栈头(元素从栈头弹出)到栈底的顺序应该是从大到小的顺序!

我来举一个例子,如图:

只有栈里从大到小的顺序,才能保证栈顶元素找到左右两边第一个小于栈顶元素的柱子。

所以本题单调栈的顺序正好与接雨水反过来。

栈顶和栈顶的下一个元素以及要入栈的三个元素组成了我们要求最大面积的高度和宽度

class Solution {
public:int largestRectangleArea(vector<int>& heights) {int result=0;//从栈顶到栈顶的顺序是从大到小stack<int>st;//存元素下标heights.insert(heights.begin(),0);//数组头部和尾部加入0heights.push_back(0);st.push(0);for(int i=1;i<heights.size();i++){if(heights[i]>=heights[st.top()])//如果当前柱子的高度 heights[i] 大于或等于栈顶柱子的高度 heights[st.top()],则将当前柱子的索引 i 压入栈中。st.push(i);//情况一和二结合体else{while(!st.empty()&&heights[i]<heights[st.top()]){int mid=st.top();st.pop();//弹出栈顶元素 mid,这代表了我们正在考虑的柱子。if(!st.empty()){int left=st.top();//获取当前栈顶元素,即左边界的索引。int right=i;//当前索引 i 作为右边界。int w=right-left-1;int h=heights[mid];result=max(result,w*h);}}st.push(i);}}return result;}
};

 如果要深刻理解的话,记得要模拟一遍代码哦。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

字节跳动(抖音)软件测试月薪23K岗、技术二面面试题最新出炉

测试人员在测试中的任务是什么&#xff1f; ① 尽可能早地找出系统中的bug&#xff1b; ② 避免软件开发过程中缺陷的出现&#xff1b; ③ 协助开发定位bug.以及后续bug跟踪 ④ 一切以用户的需求为标准&#xff0c;确保软件的质量 HTTP与HTTPS协议的区别&#xff1f; …

新160个crackme - 091-DOSKEY-CRACKME2

运行分析 需破解Name和Password PE分析 upx壳&#xff0c;32位 手动脱壳 x32dbg打开程序&#xff0c;按一下F8&#xff0c;根据ESP定律&#xff0c;在此处下断点按一下F9&#xff0c;两下F8&#xff0c;来到OEP处00401000打开Scylla&#xff0c;点击转储保存文件点击IAT自动搜索…

Python(包和模块)

包 定义 包是将模块以文件夹的组织形式进行分组管理的方法&#xff0c;以便更好地组织和管理相关模块。 包是一个包含一个特殊的__init__.py文件的目录&#xff0c;这个文件可以为空&#xff0c;但必须存在&#xff0c;以标识目录为Python包。 包可以包含子包&#xff08;子…

ClickHouse安装

一&#xff0c;ClickHouse介绍 ClickHouse 是一个开源的列式数据库管理系统&#xff08;Column-Oriented DBMS&#xff09;&#xff0c;由俄罗斯的 Yandex 公司开发。它最初是为 Yandex 的 Metrica 分析服务设计的&#xff0c;用于处理大规模的数据分析任务。ClickHouse 能够提…

网络设置:静态IP与动态IP,何去何从?

在配置网络设备时&#xff0c;一个基础而重要的选择便是决定使用静态IP地址还是动态IP地址。这一决策直接影响到网络的连接性、管理便捷性以及安全性。静态IP与动态IP各有其独特的优势与适用场景&#xff0c;选择何种方式&#xff0c;需根据实际需求与网络环境来权衡。本文旨在…

po、dto、vo的使用场景

现在项目中有两类模型类&#xff1a;DTO数据传输对象、PO持久化对象&#xff0c;DTO用于接口层向业务层之间传输数据&#xff0c;PO用于业务层与持久层之间传输数据&#xff0c;有些项目还会设置VO对象&#xff0c;VO对象用在前端与接口层之间传输数据&#xff0c;如下图&#…

不用买PSP,画质甚至更好,这款免费神器让你玩遍经典游戏

作为掌机游戏爱好者的福音&#xff0c;PPSSPP模拟器为玩家带来了前所未有的PSP游戏体验&#xff0c;彻底改变了掌机游戏的体验方式。这款精湛的软件不仅完美复刻了PSP主机的游戏体验&#xff0c;更通过先进的模拟技术&#xff0c;将经典游戏提升到了全新的高度。对于那些珍藏PS…

如何新建CANoe工程

本文将从启动CANoe软件开始&#xff0c;一步步引导您完成新工程的创建与基本配置&#xff0c;确保您的仿真测试工作能够顺利进行。 启动CANoe软件&#xff1a;打开CANoe软件&#xff0c;进入主界面。 新建工程&#xff1a;点击菜单栏的 File --> New --> CAN FD&#x…

Facebook群控策略详解

Facebook群控早在前几年就很火爆了&#xff0c;对于做Facebook营销或者电商的跨境选手来说&#xff0c;这是个不错的提高效率扩大增长的办法。具体来说&#xff0c;Facebook群控是一种通过同时管理多个Facebook账户进行自动化推广活动的方法&#xff0c;它可以实现自动发布帖子…

通讯概念-全双工、串行、同步等

1.单工&#xff0c;半双工&#xff0c;双工概念 2.串行和并行&#xff1a; 并行多根数据总线同时传输&#xff0c;需要考虑波特率情况&#xff0c;串行波特率可以很大&#xff0c;不需要考虑传输总线限制 3.同步和异步概念&#xff1a; 同步需要时钟同步&#xff0c;发送和接收…

经济下行,电商人效通过小程序快速实现多端引流

中国经济下行周期&#xff0c;消费者趋向于理性消费&#xff0c;更注重产品的实用性和性价比。中端商品的需求减少&#xff0c;低端消费人群的消费能力下降&#xff0c;导致“消费降级”现象明显。 许多线下实体店以及传统电商&#xff0c;仅仅依靠现在的模式&#xff0c;很难…

Fish Agent:集成 ASR 和 TTS 的端到端语音处理模型,支持多语言转换

❤️ 如果你也关注大模型与 AI 的发展现状&#xff0c;且对大模型应用开发非常感兴趣&#xff0c;我会快速跟你分享最新的感兴趣的 AI 应用和热点信息&#xff0c;也会不定期分享自己的想法和开源实例&#xff0c;欢迎关注我哦&#xff01; &#x1f966; 微信公众号&#xff…

软件测试工程师面试整理 —— 编程与自动化!

在软件测试领域&#xff0c;编程与自动化是提升测试效率、覆盖率和可靠性的关键因素。掌握编程技术和自动化测试框架&#xff0c;能够帮助测试人员有效地执行大量重复性测试任务&#xff0c;并迅速反馈软件的质量状况。以下是编程与自动化在测试中的主要应用及相关技术介绍&…

04字符串算法/代码随想录

四、字符串 反转字符串 力扣344 遇到数组双指针真是太好用了&#xff0c;左右指针不断逼近即可&#xff0c;代码也很简单 class Solution {public void reverseString(char[] s) {int fast s.length - 1;int slow 0;while (slow < fast) {char temp s[fast];s[fast] s[…

Unreal5从入门到精通之如何使用C++实现一个剧情系统

前言 说到剧情系统,大家可能会说,UE的关卡序列Sequencer,做剧情不是很方便吗?没错,Sequencer确实方便,而且它可以让你为场景中的角色,物体等创建精确的动画,并使用关键帧来控制他们的运动和状态变化。 它还可以做相机的移动,剪辑,音效,特效等故事情节,相机特效,多…

袋鼠云产品功能更新报告12期|让数据资产管理更高效

本期&#xff0c;我们更新和优化了数据资产平台相关功能&#xff0c;为您提供更高效的产品能力。以下为第12期袋鼠云产品功能更新报告&#xff0c;请继续阅读。 一、【元数据】重点更新 &#xff5c;01 元数据管理优化&#xff0c;支持配置表生命周期 之前系统中缺少一个可以…

将多个commit合并成一个commit并提交

0 Preface/foreword 1 压缩多个commit方法 1.1 git merge --squash 主分支&#xff1a;main 开发分支&#xff1a;test 当前在test分支提交了8个commits&#xff0c;功能已经开发完成&#xff0c;需要将test分支合并到main分支&#xff0c;但是不想在合并时候&#xff0c;看…

大数据新视界 -- 大数据大厂之提升 Impala 查询效率:重写查询语句的黄金法则(下)(4/30)

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

我想让AI帮我生成一点不正经的东西……

前言 最近突发奇想&#xff1a;为啥我一定要不断得翻找各种壁纸呢&#xff1f;为啥就不能让AI给我生成一张专属的壁纸&#xff0c;上面有我喜欢的内容&#xff0c;这样&#xff0c;我这张壁纸就是独一无二的了&#xff01; 说干就干&#xff0c;小白默默打开了AI工具…… 点我…

17、电话号码的字母组合-cangjie

题目 17、电话号码的字母组合 思路 输入处理&#xff1a; 接收一个字符串 digits&#xff0c;表示手机键盘上的数字&#xff0c;数字可以对应不同的字母组合。 边界检查&#xff1a; 如果输入字符串 digits 为空&#xff0c;返回一个空的结果列表。 按钮映射&#xff1a; 初…