Leetcode 剑指 Offer II 040. 矩阵中最大的矩形

news2025/2/23 6:07:21

题目难度: 困难

原题链接

今天继续更新 Leetcode 的剑指 Offer(专项突击版)系列, 大家在公众号 算法精选 里回复 剑指offer2 就能看到该系列当前连载的所有文章了, 记得关注哦~

题目描述

给定一个由 0 和 1 组成的矩阵 matrix ,找出只包含 1 的最大矩形,并返回其面积。

注意:此题 matrix 输入格式为一维 01 字符串数组。

示例 1:

  • 输入:matrix = [“10100”,“10111”,“11111”,“10010”]
  • 输出:6
  • 解释:最大矩形如上图所示。

示例 2:

  • 输入:matrix = []
  • 输出:0

示例 3:

  • 输入:matrix = [“0”]
  • 输出:0

示例 4:

  • 输入:matrix = [“1”]
  • 输出:1

示例 5:

  • 输入:matrix = [“00”]
  • 输出:0

提示:

  • rows == matrix.length
  • cols == matrix[0].length
  • 0 <= row, cols <= 200
  • matrix[i][j] 为 ‘0’ 或 ‘1’

题目思考

  1. 如何优化时间复杂度?

解决方案

思路

  • 分析题目, 比较容易想到的思路是动态规划, 具体做法如下:
    • dp[sr][sc][er][ec]表示左上角是(sr,sc), 右下角是(er,ec)的全 1 矩形的面积
    • 这些矩形里面如果有任意一个 0, 则其面积为 0
    • 那么如果 matrix[er][ec]dp[sr][sc][er-1][ec]dp[sr][sc][er][ec-1] 是 0 时, dp[sr][sc][er][ec]=0
    • 否则dp[sr][sc][er][ec]=dp[sr][sc][er-1][ec-1]+er-sr+ec-sc+1
    • 最终结果就是最大的 dp 值
  • 但上述做法的复杂度是 O(RCRC), 可能会超时, 如何优化呢?
  • 回想前面刚做过的题目剑指 Offer II 039. 直方图最大矩形面积, 不难发现这道题和它很类似, 都是求最大矩形面积
  • 只是这道题是矩阵, 而那道题是直方图, 有没有办法利用那道题的思路呢?
  • 我们可以维护一个高度数组, 然后遍历每一行并累加高度, 这样就把矩阵转换成了若干个直方图, 即 0~r 行矩阵形成的直方图 (0<=r<R)
  • 然后利用那道题的单调栈思路求当前直方图的最大矩形面积, 所有面积的最大值就是最终结果
  • 这里就不再赘述单调栈求最大矩形面积的过程了, 大家如果不记得的话可以参考剑指 Offer II 039. 直方图最大矩形面积
  • 下面的代码就对应了上面的整个过程, 并且有详细的注释, 方便大家理解

复杂度

  • 时间复杂度 O(RC): R 是行数, C 是列数, 矩阵每个元素最多处理 2 遍 (压入和弹出栈)
  • 空间复杂度 O©: 高度数组存 C 个元素, 单调栈最多也存 C 个元素

代码

class Solution:
    def maximalRectangle(self, matrix: List[str]) -> int:
        def largestRectangleArea(heights):
            # stack存储柱子的下标, 且其高度满足从栈顶到栈底递减
            stack = []
            res = 0
            for r, h in enumerate(heights):
                while stack and heights[stack[-1]] > h:
                    # 栈顶高度大于当前高度, 可以计算栈顶柱子对应的矩形面积了
                    # 栈顶柱子的右边界r就是当前下标, 左边界l是上一个栈顶或-1(上一个栈顶不存在时)
                    ch = heights[stack.pop()]
                    l = -1 if not stack else stack[-1]
                    # 宽*高
                    res = max(res, (r - l - 1) * ch)
                stack.append(r)
            # 如果遍历结束后栈中仍有元素, 则说明这些柱子右边没有比它更低的柱子了, 需要计算它们对应的矩形面积
            while stack:
                ch = heights[stack.pop()]
                # 栈顶柱子的右边界r就是数组长度, 左边界l是上一个栈顶或-1(上一个栈顶不存在时)
                r = len(heights)
                l = -1 if not stack else stack[-1]
                # 宽*高
                res = max(res, (r - l - 1) * ch)
            return res

        if not matrix:
            return 0
        rows, cols = len(matrix), len(matrix[0])
        heights = [0] * cols
        res = 0
        for r in range(rows):
            # 将0~r行矩阵看作以第r行为底的直方图, 求其最大矩形面积
            for c in range(cols):
                # 注意如果第r行的某个元素是0, 则其对应直方图的该列高度也是0, 而不是继续累加上一个高度
                heights[c] = heights[c] + 1 if matrix[r][c] != "0" else 0
            res = max(res, largestRectangleArea(heights))
        return res

大家可以在下面这些地方找到我~😊

我的 GitHub

我的 Leetcode

我的 CSDN

我的知乎专栏

我的头条号

我的牛客网博客

我的公众号: 算法精选, 欢迎大家扫码关注~😊

算法精选 - 微信扫一扫关注我

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

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

相关文章

c语言实现MD5算法

MD5加密 文章目录 MD5加密MD5介绍应用场景代码分析 &#xff08;基于qt5.14.2&#xff09;测试记录 MD5介绍 1。 一种单向加密算法&#xff0c;即对明文加密&#xff0c;而不能通过密文得到明文。对原数据的任何改动&#xff0c;哪怕是1字节&#xff0c;得到的MD5值都有很大的区…

C#系统锁屏事件例子 - 开源研究系列文章

今天有个网友问了个关于操作系统锁屏的问题。 我们知道&#xff0c;操作系统是基于消息和事件处理的&#xff0c;所以我们只要找到该操作系统锁屏和解屏的那个事件&#xff0c;然后在事件里进行处理即可。下面是例子介绍。 1、 项目目录&#xff1b; 下面是项目目录&#xff1a…

vue的scrollTop手机环境设置值失效,本地正常可以赋值

获取div盒子ref或者document获取都行 监听方法 一定要加this.$nexttick,在本地测试只用nexttick是没有问题的&#xff0c;但是到手机测试就不行了&#xff0c;原因是因为手机渲染比本地更快&#xff0c;所以结合setTimeout使用 如果有更好的处理方法&#xff0c;恳请大佬指点一…

C语言——通讯录详解(动态版)

通讯录详解 前言&#xff1a;一、定义一个通讯录二、初始化三、增加联系人3.1 给通讯录扩容3.2增加联系人 四、释放内存五、完整代码 前言&#xff1a; 我们已经学过了通讯录的静态版&#xff0c;但是它的缺点很明显&#xff0c;通讯录满了就添加不了联系人了啦。我再让通讯录升…

为什么要用i ,√(-1)不行吗?

首先讲一下&#xff0c;我不是拦着各位使用√(-1)&#xff0c;这只是一种记号&#xff0c;在这里只是探讨一下一些数的性质而已 我们首先需要探讨下根式的一个性质&#xff0c;下面将会讲一个关于小明的故事&#xff1a; 他的老师在黑板上写下这么一道题 一道很正常的题 他的同…

vue3 setup语法糖导入mixin

像这样直接导入&#xff0c;然后通过defineOptions声明mixin 然后就可以在这个组件使用mixin里的数据和方法了

YOLOv5复现过程出现的问题(关于数据集路径)dataset not found

YOLOv5复现过程出现的问题&#xff08;关于数据集路径&#xff09; 在复现YOLOv5时&#xff0c;按照唐老师的教程&#xff08; https://www.bilibili.com/video/BV11K41167Ar?t122.1&p63&#xff09;下载好了数据集&#xff08;MaskWearing就是检测口罩的一个&#xff0c;…

Linux常用命令——dirname命令

在线Linux命令查询工具 dirname 去除文件名中的非目录部分 补充说明 dirname命令去除文件名中的非目录部分&#xff0c;仅显示与目录有关的内容。dirname命令读取指定路径名保留最后一个/及其后面的字符&#xff0c;删除其他部分&#xff0c;并写结果到标准输出。如果最后一…

java 向上取整 java对小数取整

取整方法 Math.floor(double a) 向下取整 Math.ceil(double a) 向上取整 Math.round(double a) 四舍五入 0.5向下取整 Math.rint(double a) 就近取整 1.6接近2&#xff0c;所以就取2 1.4接近1&#xff0c;所以就取1 1.5跟1和2都很接近&#xff0c;这时候就取偶数 (int) 类型强转…

【CTF-web】buuctf-[极客大挑战 2019]EasySQL 1(sql注入)

题目链接 根据题目判断出可能需要sql注入&#xff0c;看源码可知数据是通过GET的方式传输的&#xff0c;即放在url的username和password两个参数中。 只要将username输入为1 or 11#&#xff0c;password可以为任何值&#xff0c;即可顺利登录。 需要注意的是url中的井号表示…

innovus IMPSP-270 place阶段lib_cell找不到可放置位置问题

我正在「拾陆楼」和朋友们讨论有趣的话题&#xff0c;你⼀起来吧&#xff1f; 拾陆楼知识星球入口 通过manual我们知道产生这个问题的原因有两个&#xff0c;要么没row&#xff0c;你需要重新floorplan initCoreRow&#xff0c;另外可能是设置了setPlaceMode -prerouteAsObs&a…

【PLC】上位机通过SMLP协议与三菱FX5U通信

0. 准备步骤 准备三菱 FX5U PLC 0.1 安装 GX Works3 首先点击右侧链接进入三菱官网&#xff0c;下载 GX Works3&#xff08;需要注册三菱的账号&#xff09; 若不想进官网下载也可以下载我为大家准备的网盘安装包&#xff1a;百度网盘安装包 GX Works3 下载完成后解压&#…

输入输出+暴力模拟入门:魔法之树、染色の树、矩阵、字母加密、玫瑰鸭

秋招实习刷题网站推荐&#xff1a;codefun2000.com&#xff0c;还有题解博客&#xff1a;blog.codefun2000.com/。以下内容都是来自塔子哥的~ 输入输出 2023.04.15-春招-第三题-魔法之树 //#include<bits/stdc.h> #include<vector> #include<iostream>usin…

C++ STL常用算法(详解)

C常用算法 C sort()排序函数用法详解 C STL 标准库提供有很多实用的排序函数&#xff0c;如表 1 所示。通过调用它们&#xff0c;我们可以很轻松地实现对普通数组或者容器中指定范围内的元素进行排序。 ​ 表 1 C STL 排序函数 函数名用法sort (first, last)对容器或普通数…

广度优先遍历与最短路径(Java 实例代码源码包下载)

目录 广度优先遍历与最短路径 Java 实例代码 src/runoob/graph/ShortestPath.java 文件代码&#xff1a; 广度优先遍历与最短路径 广度优先遍历从某个顶点 v 出发&#xff0c;首先访问这个结点&#xff0c;并将其标记为已访问过&#xff0c;然后顺序访问结点v的所有未被访问…

Redis在Java中的基本使用

本片将介绍 Redis 在 Java 中的基本使用 文章目录 1、使用jedis操作redis1.1、Jedis简介1.2、引入jedis的Maven依赖1.2、获取连接1.3、使用实例 2、对于JedisPooled的使用2.1、使用JedisPooled2.2、关于连接池 3、SpringBoot下使用Redis3.1、引入Maven依赖3.2、配置Redis连接3.…

POJ 1995 Raising Modulo Numbers 快速幂

一、总结 我一开始担心溢出&#xff0c;开了一个无符号的long long&#xff0c;但是直接超时&#xff0c;后来一看它的mod不是很大&#xff0c;于是改成int&#xff0c;直接过了。 二、代码 #include <iostream> using namespace std; int H, Z; int M; int mulMod(in…

【Linux操作系统】详解Linux系统编程中的管道进程通信

在Linux系统编程中&#xff0c;管道是一种常用的进程间通信方式。它可以实现父子进程之间或者兄弟进程之间的数据传输。本文将介绍如何使用管道在Linux系统中进行进程通信&#xff0c;并给出相应的代码示例。 文章目录 1. 管道的概念2. 管道的创建和使用2.1 原型2.2 示例 3. 父…

Azure Blob存储使用

创建存储账户,性能选择标准即可&#xff0c;冗余选择本地冗余存储即可 容器选择类别选择专用即可 可以上传文件到blob中 打开文件可以看到文件的访问路径 4.编辑中可以修改文件 复制链接&#xff0c;尝试访问&#xff0c;可以看到没有办法访问&#xff0c;因为创建容器的时候选…

Dubbo Spring Boot Starter 开发微服务应用

环境要求 系统&#xff1a;Windows、Linux、MacOS JDK 8 及以上&#xff08;推荐使用 JDK17&#xff09; Git IntelliJ IDEA&#xff08;可选&#xff09; Docker &#xff08;可选&#xff09; 项目介绍 在本任务中&#xff0c;将分为 3 个子模块进行独立开发&#xff…