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

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

1.题目描述

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

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

在这里插入图片描述

输入:heights = [2,1,5,6,2,3]
输出:10
解释:最大的矩形为图中红色区域,面积为 10
在这里插入图片描述

输入: heights = [2,4]
输出: 4


提示:

  • 1 <= nums1.length <= nums2.length <= 1000
  • 0 <= nums1[i], nums2[i] <= 104
  • nums1和nums2中所有整数 互不相同
  • nums1 中的所有整数同样出现在 nums2 中

2.思路分析

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

2.1 动态规划

对于下标i而言,能勾勒出的最大面积是什么?

以i为中心, 向左寻找第一个小于height[i]的位置leftMin, 向右寻找第一个小于height[i]的rightMin, 即最大面积=height[i] *(rightMin - leftMin - 1)

举个栗子:heights = [2,1,5,6,2,3],对于下标5(元素2)而言:
在这里插入图片描述

  • 定义两个长度为n的数组leftMin和rightMin

    • leftMin[i]:左边第一个小于下标i的柱子的下标
    • rightMin[i]:右边第一个小于下标i柱子的下标
  • leftMin[0] = -1 rightMin[n-1] = n

  • 正向遍历数组 height 得到数组 leftMin 的每个索引值(第一小于当前柱子高度的索引值),反向遍历数组 height 得到数组rightMin (第一小于当前柱子高度的索引值)

  • 遍历结束之后,下标i处能勾勒出的最大面积:= heights[i] * (righMin[i] -leftMin[i] - 1)

2.2 单调栈

Leetcode 42.接雨水是找每个柱子左右两边第一个大于该柱子高度的柱子,而本题是找每个柱子左右两边第一个小于该柱子的柱子。

Q1:单调栈内的元素顺序?

维护一个单调栈, 单调栈存储的元素的下标, 栈顶->栈底:递增(小->大)

一旦发现添加的柱子高度小于栈顶元素,此时就会出现凸起, 栈顶元素就是凸起顶部的柱子, 栈顶的第二个元素就是凸起左边的柱子, 当前元素就是凸起右边的柱子。
在这里插入图片描述

Q2:遇到相同柱子如何处理?

遇到相同的元素,更新栈内下标,就是将栈里元素(旧下标)弹出,将新元素(新下标)加入栈中。

单调栈的处理逻辑:

  • 情况1:当前遍历元素高度 > 栈顶元素的高度, 当前元素入栈(保持 大>小 单调的性质 )

  • 情况2: 当前遍历元素高度 == 栈顶元素高度, 更新栈顶元素(遇到相同柱子,使用右边柱子计算高度)

  • 情况3: 当前遍历元素高度 < 栈顶元素, 此时出现凸起, 弹出栈顶元素(凸起顶部柱子, 记为mid), 此时

    栈顶元素(stack.top())(凸起左边的柱子, height[st.top()]), 当前元素记为凸起右边的柱子(height[i])

    • 矩形高度: w = heights[i]
    • 矩形宽度: l = i - stack.top() -1
    • 矩形的面积:l * w

3.代码实现

3.1 动态规划

class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:
        # 动态规划
        if not heights:
            return 0
        n = len(heights)
        # 两个数组存储的下标
        leftMin = [0] * n
        rightMin = [0] * n
        result = 0

        leftMin[0], rightMin[n-1] = -1, n

        # 正向遍历数组
        for i in range(1, n):
            temp = i - 1
            while temp >= 0 and heights[temp] >= heights[i]:
                # 寻找次级柱子
                temp = leftMin[temp]
            # 寻找到左侧第一个小于当前柱子高度的下标
            leftMin[i] = temp
        # 反向遍历数组
        for i in range(n - 2, -1, -1):
            temp = i + 1
            while temp < n and heights[temp] >= heights[i]:
                # 寻找次级柱子
                temp = rightMin[temp]
            rightMin[i] = temp
        for i in range(n):
            area = heights[i] * (rightMin[i] - leftMin[i] - 1)
            result = max(area, result)
        return result

复杂度分析

  • 时间复杂度:O(n)。
  • 空间复杂度:O(n)。

3.2 单调栈

# 方式1
class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:
        heights.insert(0, 0)
        heights.append(0)
        stack = [0]
        result = 0
        for i in range(1, len(heights)):
            # 情况一
            if heights[i] > heights[stack[-1]]:
                stack.append(i)
            # 情况二
            elif heights[i] == heights[stack[-1]]:
                stack.pop()
                stack.append(i)
            # 情况三
            else:
                # 抛出所有较高的柱子
                while stack and heights[i] < heights[stack[-1]]:
                    # 栈顶就是中间的柱子,主心骨
                    mid_index = stack[-1]
                    stack.pop()
                    if stack:
                        left_index = stack[-1]
                        right_index = i
                        width = right_index - left_index - 1
                        height = heights[mid_index]
                        result = max(result, width * height)
                stack.append(i)
        return result
# 方式2
class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:
        heights.insert(0, 0)
        heights.append(0)
        stack = [0]
        result = 0
        for i in range(1, len(heights)):
            while stack and heights[i] < heights[stack[-1]]:
                mid_height = heights[stack[-1]]
                stack.pop()
                if stack:
                    # area = width * height
                    area = (i - stack[-1] - 1) * mid_height
                    result = max(area, result)
            stack.append(i)
        return result
# 方式3:
class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:
        if not heights:
            return 0
        heights.insert(0, 0)
        heights.append(0)
        stack = []
        result = 0

        for i in range(len(heights)):
            while stack and heights[i] <= heights[stack[-1]]:
                height = heights[stack.pop()]
                if stack:
                    w = i - stack[-1] - 1
                    result = max(result, height * w)
            stack.append(i)
        return result

复杂度分析

  • 时间复杂度:O(n)。
  • 空间复杂度:O(n)。

相关文章:

  • 鸿蒙智联开发者平台项目的理解介绍
  • apollo配置中心
  • 华为CSE框架的一些知识点
  • vxe-table 将表格指定行设置颜色后,选中行、悬浮行样式失效解决。
  • 这些提高摸鱼效率的自动化测试技巧,提高打工人幸福感~
  • HelloSpring
  • Vite为啥如此之快
  • 从二值 Mask 获取外接矩形坐标
  • Tomcat 的本地部署及 SmartTomcat 的使用
  • Unity Shader LightMode 标签
  • linux搭建docker镜像服务
  • 解决mybatis用Map返回的字段全变大写的问题
  • 交联剂134272-64-3,MAL-NH2 HCl 在抗体的标记上面效果明显
  • mybatis第一次课
  • 全民拼购模式:社交电商与拼购新玩法
  • docker python 配置
  • HomeBrew常规使用教程
  • JavaScript 基础知识 - 入门篇(一)
  • JavaScript设计模式与开发实践系列之策略模式
  • nginx 负载服务器优化
  • niucms就是以城市为分割单位,在上面 小区/乡村/同城论坛+58+团购
  • underscore源码剖析之整体架构
  • Vue 重置组件到初始状态
  • -- 查询加强-- 使用如何where子句进行筛选,% _ like的使用
  • 从0到1:PostCSS 插件开发最佳实践
  • 等保2.0 | 几维安全发布等保检测、等保加固专版 加速企业等保合规
  • 搞机器学习要哪些技能
  • 理解IaaS, PaaS, SaaS等云模型 (Cloud Models)
  • 悄悄地说一个bug
  • 深度学习在携程攻略社区的应用
  • 写给高年级小学生看的《Bash 指南》
  • Redis4.x新特性 -- 萌萌的MEMORY DOCTOR
  • ​io --- 处理流的核心工具​
  • ​Java并发新构件之Exchanger
  • ​直流电和交流电有什么区别为什么这个时候又要变成直流电呢?交流转换到直流(整流器)直流变交流(逆变器)​
  • # 睡眠3秒_床上这样睡觉的人,睡眠质量多半不好
  • #、%和$符号在OGNL表达式中经常出现
  • #DBA杂记1
  • #Js篇:单线程模式同步任务异步任务任务队列事件循环setTimeout() setInterval()
  • #Lua:Lua调用C++生成的DLL库
  • #QT(TCP网络编程-服务端)
  • (007)XHTML文档之标题——h1~h6
  • (1)SpringCloud 整合Python
  • (android 地图实战开发)3 在地图上显示当前位置和自定义银行位置
  • (附源码)apringboot计算机专业大学生就业指南 毕业设计061355
  • (附源码)计算机毕业设计SSM在线影视购票系统
  • (论文阅读40-45)图像描述1
  • (一)eclipse Dynamic web project 工程目录以及文件路径问题
  • (译) 函数式 JS #1:简介
  • (转)linux下的时间函数使用
  • (转)项目管理杂谈-我所期望的新人
  • .desktop 桌面快捷_Linux桌面环境那么多,这几款优秀的任你选
  • .NET Core WebAPI中使用Log4net 日志级别分类并记录到数据库
  • .NET 读取 JSON格式的数据
  • @Autowired多个相同类型bean装配问题