84. 柱状图中最大的矩形(单调栈)

news2025/3/11 3:01:36

题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

 解题思路:

方法一:暴力解法

矩形的面积由宽和高决定,可以枚举所有的高度,也就是固定高度,然后从当前高度所在的位置向两边走,分别找到左边和右边第一个小于柱子高度的位置left和right,那么right-left-1就是所求的宽度。

代码实现如下:

class Solution {
    public int largestRectangleArea(int[] heights) {
        if (heights == null || heights.length == 0) {
            return 0;
        }
        int result = 0;
        for (int i = 0; i < heights.length; i++) {
            int height = heights[i];
            int left = i-1;
            int right = i+1;
            while (left >= 0 && heights[left] >= height) {
                left--;
            }
            while (right < heights.length && heights[right] >= height) {
                right++;
            }
            int width = right - left - 1;
            result = Math.max(result, width * height);

        }
        return result;
    }
}

 上述代码的时间复杂度为O(n^2),超时了

方法二:双指针数组优化

  1. 方法一中,每一次枚举高度的时候都需要向两边寻找宽度,没有将有用的信息记录下来,在方法一种最关键的就是找到当前高度位置左右两边小于当前柱子高度的下标,每次枚举当前高度时,都需要重新找,所以可以使用两个指针数组,将当前位置左右两边小于当前柱子高度的下标记录下来,减少寻找宽度的次数
  2. 两个指针数组: 数组长度  n = heights.length
    1. minLeftIndex[ i ]:表示当前柱子 i  左边第一个小于该柱子高度的下标
      1. 初始值:minLeftIndex[0] = -1
      2. 从位置1开始从左往右求解 minLeftInde数组中的每一个值:
        1. t = i -1
        2. 如果 t >=0 && heights[ t ] >= heights[ i ],循环执行:
          1. t = minLeftIndex[ t ]:因为minLeftIndex数组是从左往右计算的,所以对于 minLeftIndex [ i ]的求解,不需要依次向左寻找小于当前柱子的下标。如果 t 位置的柱子高度大于当前柱子高度,而是利用已经求解的minLeftIndex数组,直接找到小于 t 位置柱子高度的下标 minLeftIndex [ t ],然后在判断 minLeftIndex [ t ] 位置的柱子高度是否小于当前柱子高度,如果不小于,继续该过程。可见这种方式减少了很多寻找过程
        3. minLefIndex[ i ] = t
    2. minRightIndex[ i ]:表示当前柱子 i 右边第一个小于该柱子高度的小标
      1. 初始值:minRightIndex[ n-1 ] = n
      2. 从位置 n-2 开始从右往左求解数组中的每一个值:
        1. t = i +1
        2. 如果 t < heights.length && height[ t ] >= height[ i ],循环执行:
          1. t = minRightIndex[ t ]:这里的思想和求解minLeftIndex数组类似
        3. minRightIndex[ i ] = t;
  3. 之后就可以利用已经求解的两个指针数组计算宽度,位置 i 上的柱子对应的宽度为:  width = minRightIndex[i] -minLeftIndex[i]-1

AC代码:

class Solution {
    public int largestRectangleArea(int[] heights) {
        int[] minLeftIndex = new int[heights.length];
        int[] minRightIndex = new int[heights.length];
        
        minLeftIndex[0] = -1;
        for (int i = 1; i < heights.length; i++) {
            int t = i - 1;
            while (t >= 0 && heights[t] >= heights[i]) {
                t = minLeftIndex[t];
            }
            minLeftIndex[i] = t;
        }

        minRightIndex[heights.length - 1] = heights.length;
        for (int i = heights.length - 2; i >= 0; i--) {
            int t = i + 1;
            while (t < heights.length && heights[t] >= heights[i]) {
                t = minRightIndex[t];
            }
            minRightIndex[i] = t;
        }

        int sum = 0;
        for (int i =0;i<heights.length;i++){
            int currentWidth = minRightIndex[i]-minLeftIndex[i]-1;
            int currentHeight = heights[i];
            sum=Math.max(sum,currentHeight*currentWidth);
        }
        return sum;
    }
}

 方法三:单调栈(首先是一个栈,并且从栈底到栈顶的元素有序)

  1. 单调栈内的元素满足:从栈底到栈顶元素是升序的(单调的含义,栈中元素单调有序)
  2. 单调栈适合这种场景:一维数组中要寻找任意一个元素的左边或者右边第一个比自己大或者小的元素的位置

在方法二中,双数组优化时,需要寻找左右两边第一个比当前柱子高度小的柱子的下标,所以可以使用单调栈来元素下标。

  1. 确定单调栈中元素的顺序:因为找到是左右两边第一个比当前柱子高度小的柱子的下标,所以从栈底到栈顶的元素是升序的,即栈顶元素最大。
  2. 如果当前元素小于栈顶元素,说明当前元素就是栈顶元素右边第一个高度小于栈顶元素的柱子。栈顶元素下边的那个元素就是栈顶元素左边第一个高度小于栈顶元素的柱子,此时,就可以计算栈顶元素所代表高的最大矩阵面积。计算完成之后,将栈顶元素弹出,当前元素继续和新的栈顶元素比较,如果小于,继续该过程,如果大于,当前元素入栈

特殊情况:

  1. 如果height数组本身就是升序的,那么,当前元素会一直大于栈顶元素,当前元素一直入栈,并不会计算新的矩阵大小,所以可以在数组最右边添加一个数字 0 ,避免这种情况,当出现0时,当前元素0小于栈顶元素,就会一直计算栈中柱子的高所代表的最大矩阵面积了
  2. 如果height数组本身是降序的,那么,当前元素会一直小于栈顶元素,会一直弹出栈顶元素,这个时候,栈就为空了(栈中只会保存一个元素),为了避免这种情况,可以在数组最左边添加一个0

AC代码:

class Solution {
    public int largestRectangleArea(int[] heights) {
        int result = 0;
        ArrayDeque<Integer> stack = new ArrayDeque<>();

        int[] newHeights = new int[heights.length+2];
        System.arraycopy(heights,0,newHeights,1,heights.length);
        newHeights[heights.length+1]=0;
        result = heights[0];
        
        stack.push(0);
        for (int i = 1; i < newHeights.length; i++) {
            //如果当前柱子的高度小于栈顶元素
            while (!stack.isEmpty()&&newHeights[i]<newHeights[stack.peek()]){
                int top = stack.pop();
                if (stack.isEmpty()){
                    break;
                }
                int left = stack.peek();
                int width = i - left-1;
                result = Math.max(result,width*newHeights[top]);
            }
            stack.push(i);
        }
        return result;
    }
}

 

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

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

相关文章

创新方案|超越炒作 – 从产品驱动增长PLG到产品驱动销售PLS的务实策略指南

这篇文章探讨从产品驱动增长到产品驱动销售的策略&#xff0c;超越了产品驱动增长的炒作。尽管产品驱动增长模式被认为是科技公司的灵丹妙药&#xff0c;但要取得成功&#xff0c;通常需要结合更传统的企业模式的要素。研究表明&#xff0c;只有少数采用产品驱动增长模式的公司…

生信豆芽菜-ESTIMATE预测免疫评分

网址&#xff1a;http://www.sxdyc.com/immuneEstimateScore 一、ESTIMATE预测免疫评分介绍 ESTIMATE&#xff08;Estimation of STromal and Immune cells in MAlignant Tumor tissues using Expression data&#xff09;是一种用于预测肿瘤免疫评分的计算方法。它通过分析基因…

LC-相交链表(解法2)

LC-相交链表&#xff08;解法2&#xff09; 链接&#xff1a;https://leetcode.cn/problems/intersection-of-two-linked-lists/description/ 描述&#xff1a;给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在…

生态系统NPP及碳源、碳汇模拟教程

详情点击链接&#xff1a;生态系统NPP及碳源、碳汇模拟教程 一&#xff1a;CASA模型 1.1 碳循环模型 1.2 CASA模型原理 1.3 CASA下载与安装 1.4 CASA注意事项 二&#xff1a;CASA初步操作 2.1 ENVI界面 2.2 ENVI 数据及格式 2.3 基于ENVI的CASA模拟 2.4 CASA结果分析 …

第一张Web及基础与HTTP协议

dns与域名&#xff1a; 网络是基于tcp/ip协议进行通信以及链接 应用层——传输层——网络层——数据链路层——物理层 ip地址&#xff0c;我们每一台主机&#xff0c;都有唯一的地址标识&#xff08;固定的ip地址&#xff09; ip地址的作用&#xff1a; 1&#xff0c;区分用…

一阶RC低通滤波器[原理详细推导]

注意这里面的截止频率 因为前面的推导中的复阻抗里面多了一个f 这里的的函数是: 其中: f为输入信号的频率,f_B为滤波器的截止频率。 该函数的相位角φ&#xff0c;&#xff08;为其argument的反余弦值&#xff09;: 将函数带入有: Re(H(f)) Im(H(f)) 相位角φ为: φ…

重组金黄色葡萄球菌蛋白A(Recombinant Staphylococcal Protein A, r-SPA)——一种基因工程重组蛋白

品 名&#xff1a;重组金黄色葡萄球菌蛋白A&#xff08;Recombinant Staphylococcal Protein A, r-SPA&#xff09;规 格&#xff1a;1 mg&#xff0c;10 mg&#xff0c;100 mg&#xff0c;500 mg&#xff0c;特殊订制产品形式&#xff1a;冷冻干粉&#xff1b;冻干前缓冲…

ATFX汇市:澳洲联储公布会议纪要,美元指数重归103上方

环球汇市行情摘要—— 昨日&#xff0c;美元指数上涨0.29%&#xff0c;收盘在103.17点&#xff0c; 欧元贬值0.37%&#xff0c;收盘价1.0907点&#xff1b; 日元贬值0.41%&#xff0c;收盘价145.55点&#xff1b; 英镑贬值0.06%&#xff0c;收盘价1.2687点&#xff1b; 瑞…

软考高项-思维导图34-36(计算机高级系统项目管理师)

陆续更新一些软考高项的思维导图&#xff0c;都是一些必背知识点&#xff0c;希望可以帮助大家早日考过高项&#xff0c;早日当上高工&#xff0c;早日成为杭州E类人才。全部完整导图快速获取链接&#xff1a;计算机高级系统项目管理师-思维导图汇总 三十四、需求按层次分 三十…

ReBel 论文学习笔记

论文&#xff1a;《Combining Deep Reinforcement Learning and Search for Imperfect-Information Games》 地址&#xff1a;https://arxiv.org/abs/2007.13544v2 代码&#xff1a;https://github.com/facebookresearch/rebel 材料&#xff1a; BV1gt4y1k77C&#xff08;1小时…

LC-链表的中间节点(递归)

LC-链表的中间节点&#xff08;递归&#xff09; 链接&#xff1a;https://leetcode.cn/problems/middle-of-the-linked-list/description/ 描述&#xff1a;给你单链表的头结点 head &#xff0c;请你找出并返回链表的中间结点。 如果有两个中间结点&#xff0c;则返回第二个…

Kali Linux是什么?它的主要用途是什么?

1. Kali Linux是什么&#xff1f; Kali Linux是一款基于Debian Linux的发行版&#xff0c;专注于网络安全和渗透测试。它由全球顶尖的安全专家和黑客社区维护开发&#xff0c;提供了丰富的工具和资源&#xff0c;用于测试网络、系统和应用程序的安全性。Kali Linux以其强大的功…

SpringCloud教程(中)

目录 八、Hystrix&#xff08;服务降级&#xff09; 8.1、Hystrix基本概念 8.1.1、分布式系统面临的问题 8.1.2、Hystrix是什么&#xff1f; 8.1.3、服务降级 概念 哪些情况会触发降级 8.1.4、服务熔断 8.1.5、服务限流 8.2、Hystrix案例 8.2.1、Hystrix支付微服务构…

关于vue3+niginx前端部署问题

曾经有人给我讲&#xff0c;所谓个人技术是死磕出来的&#xff0c;只有经过不断的试错和解决过程所有问题&#xff0c;以及不断变换思路去解决一件问题的过程&#xff0c;就是个人技术的成长。 最近在给自己搭建的小服务加一个bolg模块&#xff0c;在网上大概看了下轻量级的框…

发明专利写作模板和指导以及案例分析

文章目录 权利要求书说明书摘要摘要附图说明书技术领域背景技术发明内容附图说明具体实施方式 说明书附图 权利要求书 写作模板 1. 一种xxx方法&#xff0c;其特征在于&#xff0c;包括如下步骤&#xff1a;S1, &#xff08;概况介绍第一步&#xff09;&#xff1b;S2, &#x…

“深入了解Spring框架:IOC、注入方式和与Web容器的整合“

目录 1. Spring框架简介2. Spring的IOC&#xff08;控制反转&#xff09;3. Spring的注入方式3.1 第一种&#xff1a;构造函数注入3.2 第二种&#xff1a;Setter方法注入3.3 第三种&#xff1a;注解注入按名称注入&#xff08;byname&#xff09;&#xff1a;按类型注入&#x…

算法通关村第九关 | 二叉树查找和搜索树原理

1. 二分查找的扩展问题 1.1山脉数组的巅峰索引 LeetCode852&#xff1a;题目核心意思是在数组中&#xff0c;从0到i是递增的&#xff0c;从i1到数组最后是递减的&#xff0c;让你找到这个最高点。 三种情况&#xff1a; mid在上升阶段的时候&#xff0c;满足arr[mid] > a…

Docker容器与虚拟化技术:Docker容器操作、网络模式

目录 一、理论 1.Docker 容器操作 2.Docker 网络 二、实验 1.Docker 容器操作 2.Docker 网络 2.Docker 的网络模式 三、问题 1. 批量删除所有容器未生效 2.使用bridge模式指定IP运行docker报错 3.未显示bridge网络模式名称 四、总结 一、理论 1.Docker 容器操作 &a…

TVP助力数智化转型:数字物业与产业园区智慧化高质量发展

引言 数字化技术的蓬勃发展&#xff0c;为传统行业转型提供了前所未有的机遇。相较于早期的基础数字化&#xff0c;现如今数字化转型已逐步踏入更深层次。在各个领域&#xff0c;将数字技术与实际应用有机融合已日益显得迫切。如何在这一浪潮中巧妙融合数字技术与传统行业&…