Leetcode 柱状图中最大的矩形

在这里插入图片描述

h 是右边界,连续多个高度递增的柱子,如果遇到下一个 h < 栈顶元素(是最大的元素,单调递增栈),那么会不断出栈来更新计算最大面积。

并非是一次性计算出最大面积的,很重要的一点是while (!stack.isEmpty()这一部分的判断条件,会持续多次计算并更新最大面积,

你提到的情况是非常重要的,并且确实在某些情况下会让人觉得应该以栈底元素为高度,但实际上这需要从栈的完整处理流程来理解。我们仍然应该按照栈顶元素作为当前高度来计算矩形面积,而栈底元素最终也会被弹出并正确处理。

让我们详细分析这个具体输入 [5, 6, 7, 2] 的执行过程,看看为何最终仍会正确地处理到以栈底元素 5 为高度的矩形。

步骤解析:

初始化:
  • 我们的输入数组是 [5, 6, 7, 2],依然使用单调栈来计算最大矩形面积。
  • 遍历每个柱子,同时维护一个递增栈(存放柱子的索引)。
遍历开始:
  1. i = 0, heights[0] = 5

    • 栈为空,将 0 压入栈,栈为 [0]
  2. i = 1, heights[1] = 6

    • 栈顶元素对应的高度是 56 > 5,继续保持递增顺序,将 1 压入栈,栈为 [0, 1]
  3. i = 2, heights[2] = 7

    • 栈顶元素对应的高度是 67 > 6,继续递增,将 2 压入栈,栈为 [0, 1, 2]
  4. i = 3, heights[3] = 2

    • 现在,当前柱子 2 < 7,不再递增了,我们需要弹出栈顶来计算面积。
弹栈计算过程:
  1. 弹出 2 索引的柱子 (高度 7)

    • 栈顶的高度是 7,宽度为 1(因为 i - stack.peek() - 1 = 3 - 1 - 1 = 1),即矩形面积为 7 * 1 = 7
    • 更新最大面积为 7
  2. 弹出 1 索引的柱子 (高度 6)

    • 栈顶的高度是 6,宽度为 2(因为 i - stack.peek() - 1 = 3 - 0 - 1 = 2),即矩形面积为 6 * 2 = 12
    • 更新最大面积为 12
  3. 弹出 0 索引的柱子 (高度 5)

    • 栈顶的高度是 5,宽度为 3(因为栈已为空,所以宽度就是 i = 3),即矩形面积为 5 * 3 = 15
    • 更新最大面积为 15
继续遍历:
  1. 压入当前柱子 2
    • 现在将索引 3 压入栈,栈为 [3]
遍历结束:
  1. 遍历结束后,栈中还有元素 3,对应的高度是 2,我们需要处理剩余的栈:
    • 以高度 2 作为最后的矩形,高度为 2,宽度为 4(因为栈为空,宽度就是整个数组的长度 n = 4),即矩形面积为 2 * 4 = 8

最终结果:

最大面积是 15,对应的就是以高度 5 的矩形。

总结:

  1. [5, 6, 7, 2] 的案例中,当遇到比栈顶更小的 2 时,栈中的元素会依次被弹出,首先以 7 作为高度计算矩形面积,接着以 6,最后以 5。栈底元素 5 也会在这个过程中被正确地弹出,并计算出它作为高度的最大矩形面积,因此最终以栈底元素 5 为高度的矩形仍然会被正确计算

  2. 之所以使用栈顶元素作为 height,是因为栈顶元素对应的柱子是当前需要被“封闭”的柱子,当前柱子限制了栈顶柱子的右边界,所以我们需要计算以它为高度的最大矩形。

  3. 栈底元素最终也会被弹出并处理,只不过它的处理顺序是等到它的右边界被确定之后才会弹出计算,确保不会漏掉任何可能形成的更大矩形。

java solution

class Solution {public int largestRectangleArea(int[] heights) {int n = heights.length;int maxArea = 0;//栈中存放的是柱子的下标,而不是高度值Stack<Integer> stack = new Stack<>();for(int i = 0; i <= n; ++i) {//h是当前柱子的高度,当i == n 时意味着到达了我们设置的最右边界int h = (i == n) ? 0 : heights[i];//stack中的下标对应的元素值是递增的,栈顶元素作为下标所对应的元素是之前连续递增高度的最大值,//而h小于栈顶元素下标对应高度值,意味着碰到了右边界,需要我们持续出栈来多次更新计算最大面积值while(!stack.isEmpty() && h < heights[stack.peek()]) {//确定高度和宽度int height = heights[stack.pop()];int width = (stack.isEmpty()) ? i : i - stack.peek() - 1;maxArea = Math.max(maxArea, height * width);}stack.push(i);}return maxArea;}
}

关于宽度的确定

int width = stack.isEmpty() ? i : i - stack.peek() - 1;

这行代码是用于计算当前弹出的栈顶元素形成的矩形的 宽度。它看起来有点复杂,但其实逻辑很清楚:我们要确定以弹出柱子的高度为基础的矩形,它的左右边界分别是什么。

代码片段:

int width = stack.isEmpty() ? i : i - stack.peek() - 1;

这行代码的作用是计算矩形的宽度,决定矩形的左右边界。我们可以将其分为两个部分来理解。

1. 为什么需要计算宽度?

当我们从栈中弹出一个柱子时,这个柱子的高度成为当前矩形的高度,但我们还需要知道矩形的左右边界才能计算面积。

  • 右边界:当前柱子 i 的索引可以看作是右边界,因为当我们弹出栈顶元素时,当前遍历到的柱子高度 h 比栈顶柱子矮(h < heights[stack.peek()]),因此它限制了栈顶柱子的扩展。
  • 左边界:左边界取决于栈中剩下的下一个元素(也就是当前弹出的柱子左边比它更低的柱子)。如果栈中已经没有元素了,说明弹出的这个柱子可以从索引 0 开始扩展到当前索引 i - 1

2. 代码解释

int width = stack.isEmpty() ? i : i - stack.peek() - 1;

这行代码是用来计算弹出的栈顶柱子对应的矩形宽度的,有两种情况:

情况 1:栈为空(stack.isEmpty()
  • 说明:当我们弹出栈顶元素后,栈为空,意味着弹出的柱子左边没有任何柱子阻碍它的扩展。因此,弹出的这个柱子可以从索引 0 一直延伸到当前柱子的索引 i - 1
  • 宽度:在这种情况下,矩形的宽度就是从 0i - 1,即宽度为 i。所以 width = i
  • 举例:假设栈中只有一个柱子 heights[0] = 5,遍历到 i = 3,此时弹出栈顶,栈变为空,矩形宽度是 3,因为它可以从索引 0 扩展到索引 2,即 width = 3
情况 2:栈不为空(!stack.isEmpty()
  • 说明:当弹出栈顶元素后,栈中还有其他柱子,这意味着弹出的柱子左边有另一个较低的柱子阻碍它扩展。此时,弹出栈顶柱子的矩形的左边界由下一个栈顶元素(stack.peek())决定。
  • 宽度计算:矩形的宽度是从下一个栈顶元素的索引 stack.peek() 加 1,到当前柱子之前的索引 i - 1。因此,宽度为 i - stack.peek() - 1
  • 举例:假设栈中有两个柱子 heights[0] = 5heights[1] = 6,遍历到 i = 3,此时弹出 heights[1],栈中剩下 heights[0]。弹出 heights[1] 后,宽度是从 stack.peek() 位置(即 0)加 1 到当前索引 i - 1,即 3 - 0 - 1 = 2

当栈不为空时,我们的目标是计算当前弹出栈顶元素所能形成的矩形宽度,它的左右边界分别是:

  • 右边界:当前遍历到的柱子之前的索引,也就是 i - 1
  • 左边界:栈中下一个元素的索引 stack.peek(),这个元素是弹出栈顶元素左边的柱子,它限制了弹出柱子的扩展,所以左边界应是 stack.peek() + 1

因此,宽度的计算可以表示为:

width = (i - 1) - (stack.peek() + 1) + 1

简化后就是:

width = i - stack.peek() - 1

这个公式简洁地表达了矩形的宽度,涵盖了从左边界(stack.peek() 后的那一个柱子)到右边界(当前柱子的前一个位置)的距离。

你已经掌握了宽度计算的关键逻辑,非常棒!

3. 具体示例

我们用 [5, 6, 7, 2] 这个例子来展示如何计算宽度。

  • 初始状态:遍历 5, 6, 7 时,栈依次存入 [0, 1, 2]

  • 遇到 22 < 7,开始弹出栈顶元素。

    1. 弹出 7(索引 2)

      • 栈中剩下 [0, 1]7 的右边界是当前索引 3,左边界是 6 的位置(stack.peek()1)。
      • 宽度为 3 - 1 - 1 = 1,矩形面积为 7 * 1 = 7
    2. 弹出 6(索引 1)

      • 栈中剩下 [0]6 的右边界仍然是当前索引 3,左边界是 5 的位置(stack.peek()0)。
      • 宽度为 3 - 0 - 1 = 2,矩形面积为 6 * 2 = 12
    3. 弹出 5(索引 0)

      • 栈为空,所以 5 的右边界是当前索引 3,而左边界是 0
      • 宽度为 3(因为栈为空),矩形面积为 5 * 3 = 15

4. 总结

  • 宽度的计算逻辑
    • 如果栈为空,说明弹出的柱子可以扩展到最左端,即从 0 到当前索引的前一个位置,宽度为 i
    • 如果栈不为空,说明弹出的柱子左边有其他柱子阻碍,它的左边界由下一个栈顶元素的索引决定,宽度为 i - stack.peek() - 1

通过这行代码,我们可以精确地计算每个弹出栈顶柱子所能形成的最大矩形的宽度,并结合高度一起更新矩形面积。

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

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

相关文章

【Linux】多线程安全之道:互斥、加锁技术与底层原理

目录 1.线程的互斥 1.1.进程线程间的互斥相关背景概念 1.2.互斥量mutex的基本概念 所以多线程之间为什么要有互斥&#xff1f; 为什么抢票会抢到负数&#xff0c;无法获得正确结果&#xff1f; 为什么--操作不是原子性的呢&#xff1f; 解决方式&#xff1a; 2.三种加锁…

项目实战:构建 effet.js 人脸识别交互系统的实战之路

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀构建 effet.js &#x1f4d2;1. 什么是effet.js&#x1f4dc;2. 为什么需要使用effet.js&#x1f4dd;3. effet.js的功能&#x1f4da;4. 使用…

HarmonyOS NEXT 应用开发实战(五、页面的生命周期及使用介绍)

HarmonyOS NEXT是华为推出的最新操作系统&#xff0c;arkUI是其提供的用户界面框架。arkUI的页面生命周期管理对于开发者来说非常重要&#xff0c;因为它涉及到页面的创建、显示、隐藏、销毁等各个阶段。以下是arkUI页面生命周期的介绍及使用举例。 页面的生命周期的作用 页面…

聊聊Go语言的异常处理机制

背景 最近因为遇到了一个panic问题&#xff0c;加上之前零零散散看了些关于程序异常处理相关的东西&#xff0c;对这块有点兴趣&#xff0c;于是整理了一下golang对于异常处理的机制。 名词介绍 Painc golang的内置方法&#xff0c;能够改变程序的控制流。 当函数调用了pan…

T113 内核中 adbd相关配置1

准备工作 1. 配置 系统&#xff1a;ubuntu24.04docker&#xff08;ubuntu18.04&#xff09; 软件vscode, sdk:Tina-linux&#xff08;BingPi-M2&#xff09; 2. 构建环境直接使用自带的 source ./build/envsetup.sh lunch 选择 6 编译开启16线程 make -j16boot编译 mboot 打包…

设计模式——装饰者模式(8)

一、定义 指在不改变现有对象结构的情况下&#xff0c;动态地给该对象增加一些职责&#xff08;即增加其额外功能&#xff09;的模式。我们先来看一个快餐店的例子。快餐店有炒面、炒饭这些快餐&#xff0c;可以额外附加鸡蛋、火腿、培根这些配菜&#xff0c;当然加配菜需要额…

【网络安全】简单P1:通过开发者工具解锁专业版和企业版功能

未经许可,不得转载。 文章目录 前言发现过程前言 在探索一个SaaS平台的过程中,我发现了一个漏洞,使得我能够在无需订阅的情况下解锁高级(专业/企业)功能。 发现过程 我使用一个没有任何高级功能的基本用户账户进行常规登录。在浏览平台时,我注意到某些按钮和功能上带有…

基于微信小程序的购物系统【附源码、文档】

博主介绍&#xff1a;✌IT徐师兄、7年大厂程序员经历。全网粉丝15W、csdn博客专家、掘金/华为云//InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3…

web前端--html 5---qq注册

<!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta name"viewport" content"widthdevice-width, initial-scale1.0"> <title>qq注册</title> <link rel"impo…

[Linux#66][TCP->IP] 面向字节流 | TCP异常 | filesocket | 网络层IP

目录 1. 面向字节流 思考&#xff1a;对于UDP协议来说&#xff0c;是否也存在“粘包问题”呢&#xff1f; 2.TCP 异常情况 3.知识 1.UDP实现可靠传输(经典面试题) 2. 网络抓包 | 爬虫 3.打通文件和 socket 的关系 4.网络层&#xff1a;IP 前置知识 1. 面向字节流 udp…

java逻辑运算符 C语言结构体定义

1. public static void main(String[] args) {System.out.println(true&true);//&两者均为true才trueSystem.out.println(false|false);// | 两边都是false才是falseSystem.out.println(true^false);//^ 相同为false&#xff0c;不同为trueSystem.out.println(!false)…

git 安装

文章目录 一、ubuntu 安装 git二、centos 安装 git三、检查安装 git 一、ubuntu 安装 git sudo apt-get install get -y二、centos 安装 git sudo s install git -y三、检查安装 git git --version出现此标志git版本号&#xff0c;表示git安装完成。

《Effective C++》 笔记

让自己习惯C&#xff0c;Accustoming Yourself to C 1. 视C为一个语言联邦&#xff0c;View Cas a federation of languages. 将 C视为一个由相关语言组成的联邦而非单一语言。在其某个次语言&#xff08;sublanguage&#xff09;中&#xff0c;各种守则与通例都倾向简单、直观…

【win11】终端/命令提示符/powershell美化

文章目录 1.设置字体1.1. 打开win11的终端/命令提示符/powershell其中之一1.2. 打开终端设置&#xff0c;修改所有终端默认字体为新宋体 2. 修改powershell背景色为蓝色 win11的默认终端/命令提示符/powershell主题风格让人感觉与win10撕裂太大&#xff0c;尤其是字体、背景色&…

Excel:vba实现筛选出有批注的单元格

实现的效果&#xff1a;代码&#xff1a; Sub test() Dim cell As RangeRange("F3:I10000").ClearlastRow Cells(Rows.Count, "f").End(xlUp).Row MsgBox lastrow For Each cell In Range("a1:a21")If Not cell.Comment Is Nothing ThenMsgBox…

从DexMV、VideoDex、MimicPlay到SeeDo:从人类视频中学习:机器人的主流训练方法之一

前言 在此文《UMI——斯坦福刷盘机器人&#xff1a;从手持夹持器到动作预测Diffusion Policy(含代码解读)》的1.1节开头有提到 机器人收集训练数据一般有多种方式&#xff0c;比如来自人类视频的视觉演示 有的工作致力于从视频数据——例如YouTube视频中进行策略学习 即最常见…

推荐一款非常优秀的3D建模软件:PTC Creo

PTC Creo是美国PTC公司最新研发出来的一款超级强大的3D建模辅助类大型软件&#xff0c;这款软件是针对产品设计以及开发的软件&#xff0c;它具有一系列3D CAD、CAM、CAE等开发工具和套件&#xff0c;而且可用性极高。从概念设计一直到制造出产品&#xff0c;本软件都可以完成任…

Windows API 一 ----起步

目录 1.介绍主函数入口参数。 2. 简单介绍 Windows.h 这个头文件 小结&#xff0c;也聊一聊 1.介绍主函数入口参数。 第一个参数: HINSTANCE 类型的 参数&#xff0c; 称为“实例句柄“&#xff0c;这个参数唯一标志了我们写的这个程序。 第二个参数&#xff1a; HINSTANCE…

ORA-12541: TNS: 无监听程序

目录 1. 检查服务是否开启2. ip的原因 ORA-12541: TNS: 无监听程序 &#xff08;特别感谢&#xff09;参考链接&#xff1a;https://blog.csdn.net/qq_43540696/article/details/102522292 Traceback (most recent call last): File "D:\D01-software\D01010-PyCharm_co…

Java爬虫:获取直播带货数据的实战指南

在当今数字化时代&#xff0c;直播带货已成为电商领域的新热点&#xff0c;通过直播平台展示商品并进行销售&#xff0c;有效促进了产品的曝光和销售量的提升。然而&#xff0c;如何在直播带货过程中进行数据分析和评估效果&#xff0c;成为了摆在商家面前的一个重要问题。本文…