每日打卡:单调栈解决最大矩形问题(一维直方图,二维最大红矩形)

柱状图中最大的矩形

思路

这个题最明显的思路就是:矩形面积=底×高。

  • 版本1:底的长度可以通过二重循环来完成,高通过循环来寻找最小值。
  • 版本2:底的长度可以通过二重循环来完成,高通过线性比较当前遍历到的高度和之前记录的max(minh, h)

可以发现,通过遍历底×高的方法来做,优化的上限就到此为止。那么我们想一想,能否通过遍历高×底的思想呢?

如果能通过遍历每个高,这只需要O(n)的时间复杂度,同时找到以这个高度为高的最大矩形的底有多长就好了!

考虑对某一个高而言,它的底究竟是什么?如下图(参考链接)所示:

也就是我们如果能在遍历到下标为2的柱子的时候,得到这两个信息就好了:

  • 左侧比他矮的最近的柱子的下标,也就是1
  • 右侧比他矮的最近的柱子的下标,也就是4

我们想到一种结构:单调栈可以存储单调递增/递减的柱子下标。这样上面提到的第一个信息,也就是遍历时左侧比他矮的最近的柱子下标就知道了。

那么右边的呢?

右边的相当于现在的高度而言其实是“未来”的,也就是还没遍历到的。那我们考虑在“未来”的遍历过程中,无非是出现“比现在这个高度高” 和 “比现在这个高度低” 两种情况,边界的等于我们稍后再讨论。

当遇到比现在高度高时,就需要添加到栈中。因为栈必须维护 “前一个存储的下标是后一个存储下标的左边界”

当遇到比现在高度低的时候,其实就是上面提到的第二个需要知道的信息,右侧比他矮的第一个柱子的下标!

下面我们来整理一下思路:

  • 遍历每个高度,记作height
  • 单调栈维护左侧比height矮的最近的柱子的下标。称为lo。
  • 当右侧出现第一个比height矮的柱子时,计算height×底,此时底的长度是(hi-lo-1)。

而在代码实现的过程中,因为栈具有记录功能,所以上面我们所说的遍历每个高度,计算面积的过程其实不是在当前高度被遍历到的时候计算的,因为此时hi的值不知道。

我们使用栈记录了额外的信息,也就是待计算的高度height。把真正计算面积,更新最大面积的过程延迟到了hi出现的时候!我认为这才是栈作为数据结构之所以有用的原因。

而单调栈则相比栈记录了更多的信息,也就是比height矮的最近的柱子的下标lo就是height的前一个位置。

代码实现

class Solution:def largestRectangleArea(self, heights: List[int]) -> int:ans, stack = 0, []# 添加哨兵heights = [0]+heightsheights.append(0)# 左侧限位lo, 右侧限位hilo, hi = 0, 0for hi, tmp in enumerate(heights):# 注意边界条件,栈为空时直接入栈while (stack and tmp<heights[stack[-1]]):height = heights[stack.pop()]lo = stack[-1]ans = max(ans, height*(hi-lo-1))stack.append(hi)return(ans)

复杂度分析

时间复杂度

在遍历数组时,直方图的每根柱子都入栈,出栈一次,并且在每个柱子的下标出栈时计算以它为顶的最大矩形面积,这些操作对每根柱子而言复杂度都是O(1),故总的时间复杂度为O(n)

空间复杂度

需要一个辅助栈,栈中可能有O(n)根柱子在数组中的下标,故空间复杂度为O(n)

矩阵中最大的矩形

有了上面的铺垫,将一维的情况扩展至二维即可。如题:

如果把每一行/每一列看作一个heights数组,那么问题就可解了。

考虑每一行/每一列的heights应该是多少?

这里以行为例,对于第一行而言,heights应该是【10100】,第二行,则是【20211】,我们可以通过动态规划的方法更新该数组,规律为:

  • 如果位置为1,则height+1
  • 否则height变成0

为什么是正确的?因为最大的矩阵的高度永远被限制在最小的height中,所以即使我们看似加入了y轴以下的部分(有的height出现的位置早,有的出现的位置晚),也会被最小的height限制住。

代码非常简单,只是在每次调用计算柱状图中最大的矩形的外面,加了新的循环,用于更新heights数组。

class Solution:def maximalRectangle(self, matrix: List[str]) -> int:if not matrix:return 0col_len = len(matrix[0])# 记录当前行每一个“柱子”的高度,0和最后一位是哨兵heights = [0 for i in range(col_len+2)]ans, stack = 0, []for line in matrix:for i in range(col_len):# 如果是1,则长度为上一行长度+1,否则为0heights[i+1] = heights[i+1]+1 if line[i]!='0' else 0# 栈清空stack.clear()# 左侧限位lo, 右侧限位hilo, hi = 0, 0for hi, tmp in enumerate(heights):# 注意边界条件,栈为空时直接入栈while (stack and tmp<heights[stack[-1]]):height = heights[stack.pop()]lo = stack[-1]ans = max(ans, height*(hi-lo-1))stack.append(hi)return(ans)

2022-11-16 每日打卡:单调栈解决最大矩形问题(一维直方图,二维最大红矩形)相关推荐

  1. [Leedcode][JAVA][第739题][每日温度][暴力][单调栈]

    [问题描述][中等] 根据每日 气温 列表,请重新生成一个列表,对应位置的输出是需要再等待多久温度才会升高超过该日的天数.如果之后都不会升高,请在该位置用 0 来代替.例如,给定一个列表 temper ...

  2. 将一个数组中的值按逆序重新排放。_六十五、下一个更大的数系列,单调栈解决方法...

    「@Author:Runsen」 ❝ 编程的本质来源于算法,而算法的本质来源于数学,编程只不过将数学题进行代码化. 「---- Runsen」 ❞ 据说,放张小姐姐觉得照片可以提高阅读量,图是来源学校 ...

  3. 【栈】python、单调栈解决收集雨水问题、力扣42题

    以下是leetcode 42原题: 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水. 示例 1: 输入:height = [0,1,0,2,1,0,1 ...

  4. 单调栈解决取矩形问题

    单调栈解决取矩形问题 ​ 前言:这一类问题不知道是什么问题,emmm大概意思就是从一个混合着可行点和不可行点的矩形中能取出的充满可行点的矩形的数目.这一类问题应该有一个官方的名字,大家如果知道可以在评 ...

  5. LeetCode 739. 每日温度(单调栈)

    1. 题目 根据每日 气温 列表,请重新生成一个列表,对应位置的输入是你需要再等待多久温度才会升高超过该日的天数.如果之后都不会升高,请在该位置用 0 来代替. 例如,给定一个列表 temperatu ...

  6. 力扣【每日温度】leetcode-739.每日温度:单调栈解法

    题目描述: 通俗一点就是,从当前开始,往后看,看到升温的那一天目前需要等多久~ 思路: 单调栈解法:参考下一个更大元素leetcode 503题的思路以及解法 不同之处在于,题目要求返回的不是原来数组 ...

  7. 【浏览器直播源抓取】浏览器抓取真实直播源地址(2022/11/16)

    距离上次抓取直播源已经过去一年了,最近发现官方已更新了,以前的方法并不适用了,于是再来一波解析,小伙伴们准备好发车了吗? 一.版本回顾 之前直播源解析是从H5版本入手,直接从H5页面拿到全局变量liv ...

  8. 六十五、下一个更大的数系列,单调栈解决方法

    @Author:Runsen 编程的本质来源于算法,而算法的本质来源于数学,编程只不过将数学题进行代码化. ---- Runsen 据说,放张小姐姐觉得照片可以提高阅读量,图是来源学校的2020新生. ...

  9. 单调栈解决维持相对位置不变最小/最大字典序问题

    多次碰到这类维持相对位置不变,删除某些元素维持最小or最大字典序问题,这里记录一下: 首先给出一个经典的例子: 我们想要维持最小或者最大,无非是要保持相对有序的情况下,保持一个递增或者递减栈,其实就是 ...

最新文章

  1. arcgis xml 下载 切片_vue/cli3整合Cesium,加载离线arcgis 切片
  2. 国产操作系统可以基于BSD开发再闭源吗?
  3. npm: 权限阻止修复
  4. spring boot整合JPA实现多条件查询并分页
  5. mysql socket 与IP区别_MySQL本地用IP登陆而非socket
  6. puppet语法学习
  7. 99%的人都会遇到的Python “用户环境”问题
  8. AndroidStudio_在android中使用properties配置文件_进行配置_只能读取配置_不能写入配置_放在assets---Android原生开发工作笔记230
  9. python反序列化漏洞_【事件分析】No.10 影响深远的反序列化漏洞
  10. java基础——李兴华视频
  11. 【软考】中级软件设计师的一些知识点笔记(22.2.10)
  12. 70.(cesium篇)cesium接入天地图影像与注记(经纬度)
  13. Scala实现Kafka生产者与消费者实例
  14. 命令行修改微信小程序开发AppId
  15. oracle11g回闪,oracle11gdroptable后闪回-Oracle
  16. 游戏开发19课 tilemap 创建瓦片
  17. 影刀学习抓取网页详情
  18. 磁盘管理命令df和du的区别,以及du -sh ./与du -sh ./*区别
  19. 国标、行标、地标、团标、企标
  20. win10家庭版不能加入域网络

热门文章

  1. 【三维手臂手指活动动态仿真】基于MATLAB+python三维手臂动态仿真
  2. Zebra 开源框架设计
  3. 在EDIUS中使用调音台的方法
  4. 部署 TiDB Lightning
  5. Mac 如何修改用户名和用户文件夹
  6. swift有一句代码搞定APP引导页(图片/GIF/视频)
  7. Web安全-SSRF漏洞
  8. Flutter 相对布局之Stack
  9. FTL——垃圾回收GC (Garbage Collection)
  10. php递归获取文件夹,php递归遍历文件夹