DAY60 84.柱状图中最大的矩形

84.柱状图中最大的矩形

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

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

思路 

单调栈

本地单调栈的解法和接雨水的题目是遥相呼应的。

为什么这么说呢,42. 接雨水 (opens new window)是找每个柱子左右两边第一个大于该柱子高度的柱子,而本题是找每个柱子左右两边第一个小于该柱子的柱子。

这里就涉及到了单调栈很重要的性质,就是单调栈里的顺序,是从小到大还是从大到小

在题解42. 接雨水 (opens new window)中我讲解了接雨水的单调栈从栈头(元素从栈头弹出)到栈底的顺序应该是从小到大的顺序。

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

我来举一个例子,如图:

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

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

此时大家应该可以发现其实就是栈顶和栈顶的下一个元素以及要入栈的三个元素组成了我们要求最大面积的高度和宽度

理解这一点,对单调栈就掌握的比较到位了。

除了栈内元素顺序和接雨水不同,剩下的逻辑就都差不多了,在题解42. 接雨水 (opens new window)我已经对单调栈的各个方面做了详细讲解,这里就不赘述了。

主要就是分析清楚如下三种情况:

  • 情况一:当前遍历的元素heights[i]大于栈顶元素heights[st.top()]的情况
  • 情况二:当前遍历的元素heights[i]等于栈顶元素heights[st.top()]的情况
  • 情况三:当前遍历的元素heights[i]小于栈顶元素heights[st.top()]的情况

每一次入栈新元素时,我是一直向左边比较比我小的柱子,计算面积并且更新result的。这个思路好神奇我还是没有太想明白中间在while中一直在pop是怎么继续比较的。我个人认为一直在计算的是以每一个i为结尾(right)能够组成的最大矩形长度,这样理解就对了。因为如果当前的i对应的值是2,之前有5,6。即便2之后在出现6,由于2存在的原因也无法组成以5、6为高度的矩形了,所以2能够pop掉2之前所有比2大的st.top()。

class Solution {
public:int largestRectangleArea(vector<int>& heights) {int result = 0;stack<int> st;heights.insert(heights.begin(), 0);heights.push_back(0);st.push(0);for (int i = 1; i < heights.size(); ++i) {if (heights[i] > heights[st.top()]) {st.push(i);} else if (heights[i] == heights[st.top()]) {st.pop();st.push(i);} else if (heights[i] < heights[st.top()]) {while (!st.empty() && heights[i] < heights[st.top()]) {int mid = st.top();st.pop();if (!st.empty()) {int left = st.top();int right = i;int w = right - left - 1;int h = heights[mid];result = max(result, w * h);cout << mid << ' ' << left << ' ' << right << ' ' << w << ' ' << h << ' ' << result << endl;}}st.push(i);}}return result;}
};

细心的录友会发现,我在 height数组上后,都加了一个元素0, 为什么这么做呢?

首先来说末尾为什么要加元素0?

如果数组本身就是升序的,例如[2,4,6,8],那么入栈之后 都是单调递减,一直都没有走 情况三 计算结果的哪一步,所以最后输出的就是0了。 如图:

那么结尾加一个0,就会让栈里的所有元素,走到情况三的逻辑。

开头为什么要加元素0?

如果数组本身是降序的,例如 [8,6,4,2],在 8 入栈后,6 开始与8 进行比较,此时我们得到 mid(8),rigt(6),但是得不到 left。

(mid、left,right 都是对应版本一里的逻辑)

因为 将 8 弹出之后,栈里没有元素了,那么为了避免空栈取值,直接跳过了计算结果的逻辑。

之后又将6 加入栈(此时8已经弹出了),然后 就是 4 与 栈口元素 8 进行比较,周而复始,那么计算的最后结果resutl就是0。 如图所示:

所以我们需要在 height数组前后各加一个元素0。

结束啦,今天就是算法训练营的Day60!

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

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

相关文章

Doris表的动态分区

动态分区是在Doris 0.12版本中引入的新功能。旨在对表级别的分区实现生命周期管理(TTL),减少用户的使用负担。 目前实现了动态添加分区及动态删除分区的功能。动态分区只支持Range分区。 1 原理 在某些使用场景下,用户会将表按照天进行分区划分,每天定时执行例行任务,这时…

git -1

1.创建第一个仓库并配置local用户信息 git config git config --global 对当前用户所有仓库有效 git config --system 对系统所有登录的用户有效 git config --local 只对某个仓库有效 git config --list 显示配置 git config --list --global 所有仓库 git config --list…

微信小程序 prettier 格式化

一、安装prettier插件 二、打开设置 然后再打开setting.json 新增代码 {"editor.formatOnSave": true,"editor.defaultFormatter": "esbenp.prettier-vscode","prettier.documentSelectors": ["**/*.wxml", "**/*.wx…

Rust开发——变量、静态变量与常量

1.变量 在 Rust 中&#xff0c;类型安全是通过静态类型系统来实现的。变量绑定默认情况下是不可变的&#xff08;immutable&#xff09;。 在 Rust 中声明一个变量时&#xff0c;默认情况下它是不可变的。例如&#xff1a; fn main() {let x &#xff1a;i32 5; // 这是一个…

代码随想录算法训练营第三十一天| 455 分发饼干 376 摆动序列 53 最大子数组和

目录 455 分发饼干 376 摆动序列 53 最大子数组和 455 分发饼干 将胃口值与饼干进行排序使其从小到大。 从后向前遍历胃口值&#xff0c;并取得此时最大的饼干值&#xff0c;如果饼干大于当前胃口值则将答案res加一&#xff0c;并且将饼干减一。 class Solution {public in…

基于 Glibc 版本升级的 DolphinDB 数据查询性能优化实践

在高并发查询、查询需要涉及很多个分区的情况下&#xff0c;低版本的 glibc&#xff08;低于2.23&#xff09;会严重影响查询性能。需要升级 glibc 解决该问题优化性能。我们撰写了本文&#xff0c;通过 patchelf 工具修改可执行文件和动态库的 rpath&#xff0c;达到无需升级系…

专业课140+总分420+东南大学920专业综合考研,信息学院通信专业考研分享

专业课140总分420东南大学920专业综合考研&#xff0c;信息学院通信专业考研分享 我是三月开始系统考研备战&#xff0c;寒假先看的高数全书&#xff0c;奈何在家效率极其低下&#xff0c;才草草看了前三四章。回校后学习的比较认真&#xff0c;每天大概保持10个小时左右&…

3分钟看完NVIDIA GPU架构及演进

近期随着 AI 市场的爆发式增长&#xff0c;作为 AI 背后技术的核心之一 GPU&#xff08;图形处理器&#xff09;的价格也水涨船高。GPU 在人工智能中发挥着巨大的重要&#xff0c;特别是在计算和数据处理方面。目前生产 GPU 主流厂商其实并不多&#xff0c;主要就是 NVIDIA、AM…

前端为什么不能直接连数据库

其实也不是不可以&#xff0c;只是这样做有很多不好的地方&#xff0c;但是如果是一个只有几个人用的内网小系统&#xff0c;是没有问题的。主要基于以下原因考虑 安全性问题&#xff1a;前端信息都是公开的&#xff0c;从前端访问数据库&#xff0c;就需要将数据库的地址&…

学习黑马AJAX

今天开始学习黑马的AJAX课程&#xff0c;一上来就是注册案例&#xff0c;开始很不习惯axios的语法&#xff0c;感觉好别扭&#xff0c;但前面花了比较长的时间重复敲&#xff0c;现在也熟悉了很多&#xff0c;后面以为的几节课都是围绕http协议的&#xff0c;首先是url的目标资…

利用OpenCV实现图片中导线的识别

下面是一个需求&#xff0c;识别图片中的导线&#xff0c;要在图像中检测导线&#xff0c;我们需要采用不同于直线检测的方法。由于OpenCV没有直接的曲线检测函数&#xff0c;如同它对直线提供的HoughLines或HoughLinesP&#xff0c;检测曲线通常需要更多的图像处理步骤和算法&…

java io流中为什么使用缓冲流就能加快文件读写速度

FileInputStream的read方法底层确实是通过调用JDK层面的read方法&#xff0c;并且这个JDK层面的read方法底层是使用C语言编写的&#xff0c;以实现高效的文件读取功能。但是它会涉及多次内核态与操作系统交互。当我们使用FileInputStream的read方法读取文件时&#xff0c;首先会…

UEC++ day7

敌人NPC机制 敌人机制分析与需求 新建一个character类来作为敌人&#xff0c;直接建蓝图设置骨骼网格&#xff0c;因为敌人可能多种就不规定死&#xff0c;然后这个敌人肯定需要两个触发器&#xff0c;一个用于大范围巡逻&#xff0c;一个用于是否达到主角近点进行攻击 注意我…

【Flink】Process Function

目录 1、ProcessFunction解析 1.1 抽象方法.processElement() 1.2 非抽象方法.onTimer() 2、Flink中8个不同的处理函数 2.1 ProcessFunction 2.2 KeyedProcessFunction 2.3 ProcessWindowFunction 2.4 ProcessAllWindowFunction 2.5 CoProcessFunction 2.6 ProcessJo…

https和http的区别和优势

大家好&#xff0c;我是咕噜-凯撒&#xff0c;HTTP&#xff08;超文本传输协议&#xff09;和HTTPS&#xff08;安全超文本传输协议&#xff09;是用于在网络上传输数据的协议&#xff0c;HTTPS相比HTTP在数据传输过程中更加安全可靠&#xff0c;适合对数据安全性要求较高的场景…

ventoy安装操作系统

下载ventoy https://github.com/ventoy/Ventoy/releases/download/v1.0.96/ventoy-1.0.96-windows.zip 解压后执行 Ventoy2Disk 2、安装后将ISO放入U盘大的分区&#xff0c;通过U盘启动就可以识别到ISO镜像开始装系统

MySQL 日志管理、备份与恢复

一、MySQL 日志管理 MySQL 的日志默认保存位置为 /usr/local/mysql/data vim /etc/my.cnf [mysqld] ##错误日志&#xff0c;用来记录当MySQL启动、停止或运行时发生的错误信息&#xff0c;默认已开启 log-error/usr/local/mysql/data/mysql_error.log #指定日志的保存位置…

PDF控件Spire.PDF for .NET【转换】演示:将 PDF 转换为 word、HTML、SVG、XPS

本文我们将演示如何通过调用 Spire.PDF 提供的方法 PdfDocument.SaveToStream() 将 PDF 页面转换为 HTML、Word、SVG、XPS、PDF 并将它们保存到流中。并且从Spire.PDF版本4.3开始&#xff0c;它新支持转换定义范围的PDF页面并将其保存到流中。 Spire.Doc 是一款专门对 Word 文…

springboot项目基于jdk17、分布式事务seata-server-1.7.1、分库分表shardingSphere5.2.1开发过程中出现的问题

由于项目需要&#xff0c;springboot项目需基于jdk17环境开发&#xff0c;结合nacos2.0.3、分布式事务seata-server-1.7.1、分库分表shardingSphere5.2.1等&#xff0c;项目启动过程中出现的问题解决方式小结。 问题一&#xff1a; Caused by: java.lang.RuntimeException: j…