每日一题——柱状图中最大的矩形

news2024/11/25 2:30:52

柱状图中最大的矩形

题目链接


用什么数据结构?

要得到柱状图中最大的矩形,我们就必须要知道对于每一个高度heights[i],他所能勾勒出的矩形最大是多少(即宽度最大是多少)。

而对应到图上我们可以知道,要知道最大宽度,那就需要通过对下标的计算得到,因此要存储的也应该是每个高度对应的下标

即:通过存储的下标索引找到对应的高度,同时快速计算出宽度,最终得到面积

我们就拿上面的例子进行分析:

  • 一开始遍历的柱形高度是2,但以这一高度所确定的矩形还不能确定其面积的最大值,因此继续遍历

  • 第二个柱形高度为1,此时这一高度所确定的最大矩形还不能确定。但是它前面的下标为0的柱形所确定的最大矩形就可以确定了。因为下标为1的这个柱形高度比下标为0的小,矮的卡在了高的后面,那么这个高的就不能向右扩展了
    • 这个时候,我们也就能计算下标为0的这一高度所能确定的最大矩形的面积了。同时,既然这一下标的高度已经确定,我们也就可以忽略这一下标代表的高度了,我们将其标灰。

  • 第三个高度为5,由同样的分析可得,下标为2和下标为1的高度都不能确定其最大的矩形。继续遍历。

  • 第四个高度为6,同样,高度为1,5,6的三个柱形也同样不能确定最大的矩形,继续便利。

  • 第五个高度为2,小于下标为3的高度,因此下标为3高度为6的柱形确定的最大矩形就知道了。面积size = 6 * (4-2-1) = 6,同时由于这个柱形已经计算,就将其忽略、标灰。

    • 下标为4高度为2的柱形仍低于下标为2高度为5的柱形,因此下标为2高度为5的柱形确定的最大矩形也就知道了。面积size = 5 * (4-1-1) = 10,同时将这一柱形忽略、标灰。

    • 下标为4高度为2的柱形高于下标为1高度为1的柱形,因此这两个柱形仍不能确定其最大的矩形,继续遍历。

  • 第六个的高度为3,由同样的分析,高度为1,2,3的柱形都不能确定其最大的矩形

此时我们就遍历完了整个heights数组,但是我们还有三个高度的最大矩形还没有确定,为了处理这三个数据,我们可以假设下标为6的柱形的高度为0(小于1都可以)

  • 这样,下标为5高度为3的柱形就被夹在了两个较矮柱形的中间,其最大矩形也就确定了。size = 3 * (6-4-1) = 3

  • 同理,下标为4高度为2的矩形面积为:size = 2 * (6-1-1) = 8

在这里插入图片描述

  • 此时,只剩下下标为1高度为1的柱形,他是所有柱形中最低的柱形,所以它最大矩形的宽度就是整个数组的长度,因此面积size = 1 * 6 = 6

至此,每个柱形所确定的最大矩形都已经分析完毕。

由上面的分析我们可以得出以下结论:

  1. 存储下标时,我们是从左到右存储的,但是计算下标对应的高度所确定的矩形面积时,是从右向左计算的(例如是先计算高度为6的面积在计算高度为5的面积),这符合先入后出的特性,因此这一题我们要用到的数据结构是栈
  2. 之所以能确定一个柱形的最大矩形,就是在他右边碰到了比他更低的柱形(因为这个更低的柱形限制了这个高柱形的扩张)。因此这个栈存放的下标对应的高度应该是单调非递减的(注意不是单调递增)只要碰到递减的情况,就说明可以计算栈顶元素所代表高度的矩形面积了
  3. 这个栈之所以要单调非递减时要考虑到进栈元素等于栈顶元素的情况。如下图:

  • 如果将栈设计为单调递增的,那么当进栈元素5入栈时,栈顶元素5就要出栈,并计算其面积,但问题是这个进栈元素5并不小于这个栈顶元素5,那么这个栈顶元素5所确定的最大矩形也就不能确定。
  • 因此进栈元素等于栈顶元素时,栈顶元素不要出栈。即这个栈为单调非递减的

考虑特殊情况(添加哨兵位)

  • 情况一:计算宽度时栈空。如下图:

此时,栈中存储的下标为[0],进栈下标对应的高度小于栈顶元素对应的高度,栈顶元素需要出栈,并计算其高度对应的最大矩形。现在问题来了,栈顶元素出栈后栈为空,没有下标用来计算宽度,这里就要用if(stackEmpty)来进行特殊处理,但显然这是不方便的。因此我们可以在heights数组的最前面加入一个高度0,这样我们就可以保证栈中始终留有数据(这个0不可能出栈),也就可以更加方便的计算宽度了。

  • 情况二:遍历完heights数组后,栈中还留有有效数据(部分柱形的最大矩形还未确定),如下图:

要计算出每个柱形的最大矩形,也就是要将栈中的每个下标都出栈,而要确保每个下标都可以出栈,那就要保证进栈下标代表的高度要小于栈中元素对应的高度,因此我们可以在heights数组的末尾再加上一个0,这样就可以保证在遍历完heights数组的同时,每个高度的最大矩形都可以被计算了。

这两个高度为0,站在数组两边的柱形,就是我们常说的哨兵

实现代码

int largestRectangleArea(int* heights, int heightsSize){
    //添加哨兵位:
    heights = (int*)realloc(heights, sizeof(int) * (heightsSize + 2));
    heights[heightsSize + 1] = 0;	//尾部添加0
    for (int i = heightsSize; i > 0; i--)
        heights[i] = heights[i - 1];
    heights[0] = 0;	//头部添加0

    int *stack = (int*)malloc(sizeof(int) * (heightsSize + 2));
    int top = 0;
    int ret_size = 0;

    for (int i = 0; i < heightsSize + 2; i++)
    {
        //当栈不为空并且进栈元素小于栈顶元素
        //就开始计算矩形面积
        while (top != 0 && heights[i] < heights[stack[top - 1]])
        {
            //栈顶元素出栈
            int high_index = stack[top - 1];
            top--;

            int wide = i - stack[top - 1] - 1;	//宽度
            int high = heights[high_index];	//高度
            ret_size = ret_size > wide * high ? ret_size : wide * high;
        }
		
        //计算完成后或者没有进入循环,进栈元素都要入栈
        stack[top++] = i;
    }

    free(stack);	//释放栈

    return ret_size;
}

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

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

相关文章

vue naive ui 按钮绑定按键

使用vue (naive ui) 绑定Enter 按键 知识点: 按键绑定Button全局挂载使得message,notification, dialog, loadingBar 等NaiveUI 生效UMD方式使用vue 与 naive ui将vue默认的 分隔符大括号 替换 为 [[ ]] <!DOCTYPE html> <html lang"en"> <head>…

助力养殖行业数字化转型,基于深度学习模型开发构建牛脸识别系统

在我们以往接触到的项目或者是业务场景中&#xff0c;大多牵涉到生物特征识别的任务基本都是人脸识别&#xff0c;这也是目前我们每天都会接触到的应用&#xff0c;比如&#xff1a;上下班的打卡、支付时的刷脸等等&#xff0c;这也是比较成熟的一项AI应用。 这里我们简单对一…

用智能汽车完成自救,高通的光明与暗夜!

这几年国产汽车的在智驾驶的发力&#xff0c;无疑受到了各行各业的瞩目&#xff0c;汽车智能化已经逐步走进大众视野。 我们之前阐述过高通在3C数码领域的见解与财报预测&#xff0c;随着第三财季的业绩报告显示&#xff0c;可以看到的是智能手机、IoT 市场的低迷让高通的营收…

C#调用barTender打印标签示例

使用的电脑需要先安装BarTender 我封装成一个类 using System; using System.Windows.Forms;namespace FT_Tools {public class SysContext{public static BarTender.Application btapp new BarTender.Application();public static BarTender.Format btFormat;public void Q…

vivado复制工程后如何修改路径

在 vivado 工程复制之后&#xff0c;直接打开项目&#xff0c;会发现所有文件都指向原工程&#xff0c;这个问题困扰了我好久&#xff08;之前都是项目中 remove 之后再一个一个重新添加&#xff0c;特别麻烦&#xff09;。然而前几天突发奇想试着把除 .srcs 文件夹之外的所有文…

大规模数据爬取 - 增量和分布式爬虫架构实战

嗨&#xff0c;亲爱的爬虫开发者们&#xff01;在当今的数据驱动时代&#xff0c;大规模数据的爬取对于许多领域的研究和应用至关重要在本文中&#xff0c;我将与你分享大规模数据爬取的实战经验&#xff0c;重点介绍增量和分布式爬虫架构的应用&#xff0c;帮助你高效地处理海…

AUTOSAR DEM (一):简介

AUTOSAR DEM &#xff08;一&#xff09;:简介 故障事件触发故障信息上报故障信息处理故障事件存储DEM与其他模块的联系 缩略词说明 abbreviationdescriptionDEMDiagnostic event managerDTCDiagnostic Trouble CodeBSWBasic softwareSWCSoftware componenECUMECU state manag…

Java 大厂面试 —— 常见集合篇 List HashMap 红黑树

23Java面试专题 八股文面试全套真题&#xff08;含大厂高频面试真题&#xff09;多线程_软工菜鸡的博客-CSDN博客 常见集合篇-01-集合面试题-课程介绍 02-算法复杂度分析 2 List相关面试题 2.1 数组 2.1.1 数组概述 数组&#xff08;Array&#xff09;是一种用连续的内存空…

Win11 重启资源管理器的方法

方法一&#xff1a;按【Ctrl Alt Del】组合键后&#xff0c;调出锁定界面&#xff0c;然后点击【任务管理器】即可 方法二&#xff1a;按【Ctrl Shift ESC】组合键后&#xff0c;会直接调出任务管理器 1、在任务管理器窗口中&#xff0c;找到名称为【Windows 资源管理器】…

使用synchronized关键字同步类方法

要想解决“脏数据”的问题&#xff0c;最简单的方法就是使用synchronized关键字来使run方法同步&#xff0c;代码如下&#xff1a; public synchronized void run() { } 从上面的代码可以看出&#xff0c;只要在void和public之间加上synchronized关键字&#xff0c;就可以…

内网远程控制总结

前言 在内网渗透过程中&#xff0c;会碰到远程控制soft或者其他&#xff0c;这里针对远程控制软件做如下总结。 远程控制软件 向日葵篇 向日葵查看版本 向日葵&#xff08;可以攻击&#xff09; 针对向日葵的话其实如果有本地安装的话&#xff0c;是有可能存在漏洞的。这…

[CKA]考试注意事项及作者考试结果

在CKA考试的时候&#xff0c;注意目前可以使用中文名进行注册&#xff0c;最后证书上的名字也是中文名 考试前准备&#xff1a; 1、身份证 2、桌面除了电脑鼠标其他物品都收好 3、房间就自己一个人&#xff0c;不允许房间有其他人 4、网速要快&#xff0c;博主特意升级了自…

GBU814-ASEMI功率整流器件GBU814

编辑&#xff1a;ll GBU814-ASEMI功率整流器件GBU814 型号&#xff1a;GBU814 品牌&#xff1a;ASEMI 封装&#xff1a;GBU-4 恢复时间&#xff1a;&#xff1e;50ns 正向电流&#xff1a;8A 反向耐压&#xff1a;1400V 芯片个数&#xff1a;4 引脚数量&#xff1a;4 …

CGLIB代理,jsp,EL表达式,JSTL标准标签库

1、CGLIB代理 有一个类没有实现接口&#xff0c;想要对这个类实现增强&#xff0c;就需要使用CGLIB代理 导入CGLIB的包 <dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version> </depende…

集成易点易动管理系统连接更多应用

场景描述&#xff1a; 基于易点易动开放平台能力&#xff0c;无代码集成易点易动与多个应用互通互连&#xff0c;实现固定资产管理数字化、智能化。通过Aboter可搭建业务自动化流程&#xff0c;实现多个应用之间的数据连接。 开放能力&#xff1a; 消息推送&#xff1a; 新…

无涯教程-分类算法 - 多项式逻辑回归模型函数

Logistic逻辑回归的另一种有用形式是多项式Lo​​gistic回归&#xff0c;其中目标或因变量可以具有3种或更多可能的unordered类型&#xff0c;即没有定量意义的类型。 用Python实现 现在&#xff0c;无涯教程将在Python中实现上述多项式逻辑回归的概念。为此&#xff0c;使用…

前端js实现获取指定元素(top,lef,right,bottom)到视窗的距离 ;getBoundingClientRect()获取

getBoundingClientRect()获取元素位置&#xff0c;这个方法没有参数 该函数返回一个Object对象&#xff0c;该对象有6个属性&#xff1a;top,lef,right,bottom,width,height&#xff1b; <div id"box"></div>var objectdocument.getElementById(box); …

产教融合 | 中南大学暑期实训,用万应低代码践行敏捷开发之路

融合学究与实践&#xff0c;方能成为当代“数字英才”。 2023年8月11日&#xff0c;由潇湘大数据研究院、中南大学计算机学院及云畅科技联合组织的2020级数据科学与大数据技术专业暑期‘生产实训’项目圆满结束。本次实训全程线下进行&#xff0c;基于“深度创新培育计划”&…

宇凡微Y51T合封射频芯片,集成433M芯片和MCU

宇凡微推出的Y51T芯片的设计理念很有趣&#xff0c;将MCU和射频芯片集成在一颗芯片内&#xff0c;从而实现高度的集成度和功能优势。这样的设计在某些应用中确实能够带来诸多优点&#xff1a; Y51T将51H MCU和Y4455 433MHz射频芯片融合在一颗芯片内&#xff0c;实现了高度集成的…

GPU中统一内存最新机制解析

通过异构内存管理简化 GPU 应用程序开发 异构内存管理 (HMM) 是一项 CUDA 内存管理功能&#xff0c;它扩展了 CUDA 统一内存编程模型的简单性和生产力&#xff0c;以包括具有 PCIe 连接的 NVIDIA GPU 的系统上的系统分配内存。 系统分配内存是指最终由操作系统分配的内存&#…