当前位置: 首页 > news >正文

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!

相关文章:

  • U4_1:图论之DFS/BFS/TS/Scc
  • 【鸿蒙应用ArkTS开发系列】- 灌水区,鸿蒙ArkTs开发有问题可以在该帖中反馈
  • 【深入理解Typescript】—— 第一章:为什么要使用Typescript
  • Me-and-My-Girlfriend-1
  • visionOS空间计算实战开发教程Day 1:环境安装和编写第一个程序
  • 自动驾驶相关
  • 【JavaEE初阶】计算机是如何工作的
  • HarmonyOS ArkTS List组件和Grid组件的使用(五)
  • 【开源】基于微信小程序的音乐平台
  • unity DontDestroyOnLoad后跳转场景后不会出现重复物体
  • linux rsyslog综合实战2
  • 没收到Win11 23H2正式版的推送怎么升级到23H2
  • Android 10-13鼠标右键返回功能适配
  • 观察者模式的运用——消息队列
  • 代码随想录算法训练营第三十一天| 455 分发饼干 376 摆动序列 53 最大子数组和
  • 【翻译】babel对TC39装饰器草案的实现
  • Elasticsearch 参考指南(升级前重新索引)
  • hadoop入门学习教程--DKHadoop完整安装步骤
  • node和express搭建代理服务器(源码)
  • React as a UI Runtime(五、列表)
  • 闭包,sync使用细节
  • 动态魔术使用DBMS_SQL
  • 理解在java “”i=i++;”所发生的事情
  • 面试总结JavaScript篇
  • 由插件封装引出的一丢丢思考
  • 怎么把视频里的音乐提取出来
  • ​云纳万物 · 数皆有言|2021 七牛云战略发布会启幕,邀您赴约
  • #include
  • (1)STL算法之遍历容器
  • (42)STM32——LCD显示屏实验笔记
  • (day 2)JavaScript学习笔记(基础之变量、常量和注释)
  • (iPhone/iPad开发)在UIWebView中自定义菜单栏
  • (Mirage系列之二)VMware Horizon Mirage的经典用户用例及真实案例分析
  • (ros//EnvironmentVariables)ros环境变量
  • (附源码)spring boot车辆管理系统 毕业设计 031034
  • (已解决)vue+element-ui实现个人中心,仿照原神
  • (转)C#调用WebService 基础
  • (转)IIS6 ASP 0251超过响应缓冲区限制错误的解决方法
  • (转载)微软数据挖掘算法:Microsoft 时序算法(5)
  • .Net Framework 4.x 程序到底运行在哪个 CLR 版本之上
  • .net 反编译_.net反编译的相关问题
  • .netcore如何运行环境安装到Linux服务器
  • .net安装_还在用第三方安装.NET?Win10自带.NET3.5安装
  • .net获取当前url各种属性(文件名、参数、域名 等)的方法
  • /usr/bin/perl:bad interpreter:No such file or directory 的解决办法
  • @ 代码随想录算法训练营第8周(C语言)|Day53(动态规划)
  • @value 静态变量_Python彻底搞懂:变量、对象、赋值、引用、拷贝
  • [100天算法】-目标和(day 79)
  • [C/C++]数据结构 堆的详解
  • [CF494C]Helping People
  • [Codeforces1137D]Cooperative Game
  • [Docker]十二.Docker consul集群搭建、微服务部署,Consul集群+Swarm集群部署微服务实战
  • [GN] Vue3.2 快速上手 ---- 核心语法2
  • [IDF]摩斯密码
  • [Jquery] 实现鼠标移到某个对象,在旁边显示层。