Leetcode 85. 最大矩形

题目信息

LeetoCode地址: 力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

题目理解

该题是84题的升级版。84题给出了一个一维数组,即一行数据,每个元素是高度。而该题则是给出了二维数组,只需我们将每一行的高度自行求出,即可以运用相同的算法解决。

该题目的难点在于思维模型上,如何借助单调栈和数组给出的信息进行快速求解。

以示例1为例:

如果将每一行的1的高度(即连续的1的长度)以橙色标注出来,会发现只包含1的最大矩形出现在第三行里,2*3=6.

不难发现,每一个矩形都是由一列一列1组成的,我们要找到的就是能够组成最大矩形的那些列!

要找到它,我们需要总结一些规律

  • 矩形的长度和高度越大越好
  • 矩形的每一列高度一定相等

是的,只需要关注上面两条规略就足够了!我们在遍历每一行元素时,如果遇到某一列比之前的列小,那它就一定和之前比它高的列(同一行之前的列)没有任何关系了!此时需要回过头来算账,计算之前那些更高的列能够组成的最大矩阵有多大?高度我们已经确定,唯一需要确定的就是长度,即维持该高度的左右下标。显然,我们应该使用一种数据结构存储这样的下标,由于我们要倒着拿下标数据,栈就是最合适的了。那什么时候存下标呢?由于我们遇到更短的列时才会倒着拿数据,那当然要在当前列不短于上一列的情况下去插入下标了!!

口说无凭,让我们根据第三行的列高度数据来推演一下吧!

heightArray[2] = {3,1,3,2,2}

stack = {}

最初时栈是空的,此时是没有数据给你复盘的,所以我们要把3的下标存入栈
stack = {0}

然后我们看第二个元素1,糟糕,它比第一列还要短,它帮不上前面的列的忙了,所以我们要往回看,直到栈空,或者展栈内元素都不小于1.

由于栈里只有3,所以我们分析高度不小于3的列的左右下标。左下标显然是-1,因为不存在其他元素了。又下标则是当前元素1的下标1. 然后我们就可以更新一下可能的最大矩形面积=(右下标-左下标-1) * 高度 = (1-(-1) -1)* 3 = 3.

与第一列有关系的最大矩形求完了,它的下标也没有继续呆在栈里的意义了,所以我们出栈,继续上一过程,直到栈空,或者展栈内元素都不小于1.

很显然,3出栈完后这一过程就结束了,我们可以将第一列的1下标入栈,继而遍历低3列下标2的高度。又是3!而且比第二列大,它能帮的上忙!所以我们将它入栈。

stack = {1,2}

继续看第4列,嗯,它比栈顶元素高度3小,所以我们要重复上面出栈的过程。

可能的最大矩形面积= (3-1-1)*3 = 3.

栈顶2出栈后,新栈顶的高度和当前列的高度一样的,所以我们不再出栈,继续放入该列下标

stack={1,3}

继续看第5列,它和栈顶元素高度一样大,入栈!

stack={1,3,4}

至此,该行的所有元素都遍历完了,但是我们的工作并没有结束。因为栈还没有空。很显然,现在栈里每一个元素的高度,都可以维持到该行的最后一个元素!

所以我们要一个一个出栈,计算它们到该行最右边列所可能组成的最大矩形面积

对于下标4,可能的最大矩形面积= (5-3-1)*2 = 2.

对于下标3,可能的最大矩形面积= (5-1-1)*2 = 6.

对于下标1,可能的最大矩形面积= (5-(-1)-1)*1 = 5.

该行结束。其余的每一行都是按照该方法进行遍历,最后可以很容易得到最终答案6.

单调栈 写法

在实现上有一个小技巧,我们不用真的使用Deque,Stack等封装类,仅仅使用一个数组+指针的方式即可模拟栈,在时间效率上会更高。

public int maximalRectangle(char[][] matrix) {
        int max = 0;
        int h = matrix.length;
        int l = matrix[0].length;
        int[] heights = new int[l];
        for (int i = 0; i< h;i++) {
            //该循环可以累计每行的高度
            for (int j = 0; j < l; j++) {
                if (matrix[i][j] == '0') {
                    heights[j] = 0;
                } else {
                    heights[j]++;
                }
            }
            max = Math.max(max, findMax(heights));
        }
        return max;
    }

    private int findMax(int[] heights) {
        int l = heights.length;
        //使用数组模拟栈
        int[] stack = new int[l];
        // 栈顶指针, 值为-1时代表该栈为空
        int stackTopIdx = -1;
        int i = 0;
        int max = 0;
        while (i < l) {
            //栈空时入栈
            if (stackTopIdx == -1) {
                stack[++stackTopIdx] = i++;
            } else {
                //当前列高度大于等于栈顶,入栈
                if (heights[i] >= heights[stack[stackTopIdx]]) {
                    stack[++stackTopIdx] = i++;
                } else {
                    //当前列高度小于栈顶列,出栈结算直到栈空或者栈顶列高度小于等于当前列
                    //注意,该分支内i的值是没有++的,会循环遍历直到满足上述条件
                    int height = heights[stack[stackTopIdx--]];
                    int leftIndex = stackTopIdx <= -1 ? -1 : stack[stackTopIdx];
                    int rightIndex = i;
                    max = Math.max(max, (rightIndex-leftIndex-1) * height);
                }
            }
        }
        //该行所有列都遍历完栈还不为空,说明最后若干列高度越来越大
        //我们需要手动出列计算它们能够组成的最大矩形
        while (stackTopIdx>=0) {
            int height = heights[stack[stackTopIdx--]];
            int leftIndex = stackTopIdx <= -1 ? -1 : stack[stackTopIdx];
            max = Math.max(max, (l-leftIndex-1) * height);
        }
        return max;
    }

在Matrix 高m, 长n的规模下

时间复杂度: O(m*n),最复杂的操作是遍历每行列高度,以及在每一行里找寻最大矩阵

额外空间复杂度: O(n),我们需要一个临时数组存储每行的列高度,以及栈。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

太强了,AI数字人从制作到变现一次搞定

AI数字人从制作到变现 如果说GPT类大模型是我们人类的第二大脑&#xff0c;数字人就是我们人类在互联网上的第二个身体。随着 AI 的迅速发展&#xff0c;2024 年 AI 模型开始从大型语言模型向大型视觉模型转变。数字人技术作为其分支之一&#xff0c;正日益成为科技、娱乐、教…

【GAMES101】Lecture 14 15 辐射度量学

目录 辐射度量学 Radiant flux&#xff08;光通量&#xff09; intensity&#xff08;发光强度&#xff09; irradiance radiance 辐射度量学 主要讲述了物理学中的Basic radiometry (辐射度量学)&#xff0c;就是我们在之前的计算光照中没有用具体的物理单位去衡量和描述…

C++新特性 协程

本篇文章我们来讲述一下C协程 协程&#xff08;Coroutine&#xff09;是一种能够挂起个恢复的函数过程 是一种轻量级的并发编程方式&#xff0c;也称为用户级线程。它与传统的线程&#xff08;Thread&#xff09;相比&#xff0c;具有更低的开销和更高的执行效率。 协程通常运…

爬虫学习笔记-scrapy爬取汽车之家

1.终端运行scrapy startproject scrapy_carhome,创建项目 2.接口查找 3.终端cd到spiders,cd scrapy_carhome/scrapy_carhome/spiders,运行 scrapy genspider audi https://car.autohome.com.cn/price/brand-33.html 4.打开audi,编写代码,xpath获取页面车型价格列表 5.运行项目…

深度学习技巧应用35-L1正则化和L2正则在神经网络模型训练中的应用

大家好,我是微学AI,今天给大家介绍一下深度学习技巧应用35-L1 正则化和L2正则在神经网络模型训练中的应用。L1正则化和L2正则化是机器学习中常用的两种正则化方法,用于防止模型过拟合并提高模型的泛化能力。这两种正则化方法通过在损失函数中添加惩罚项来控制模型的复杂性。…

面试八股文(4)

文章目录 1.sleep和wait区别2.为什么调用start()方法会执行run()方法&#xff0c;为什么不能直接调用run()方法3.synchronized关键字4.并发编程的三个重要特性5.synchronized和volatile关键字区别6.ThreadLocal7.为什么要用线程池&#xff1f;8.实现Runnable接口和Callable接口…

课时13:变量基础_变量场景

2.1.1 变量场景 学习目标 这一节&#xff0c; 我们从 数据存储、变量场景、小结 三个方面来学习。 数据存储 数据存储 所谓的数据存储&#xff0c;我们从三方面来理解这句话&#xff1a;1、数据保存到哪里 -- 各种媒介&#xff0c;CPU、内存、磁盘、磁带、网盘...2、数据保…

react+ts+antd-mobile 动态tabs➕下拉加载

1.初始化项目 //搭建项目 npm create vitelatest react-jike-mobile -- --template react-ts//安装依赖 npm i //运行 npm run dev清理项目目录结构 安装ant design mobile ant design mobile是ant design家族里专门针对于移动端的组件库 npm install --save antd-mobile测试…

日志报错 git -c dif.mnemonicprefix=false -c core.guotepath=false 解决方法

前言: 在进行下面操作前,必须确保,你是否安装了Git。 查看Git 在命令行窗口中输入`git --version`: 如果这个命令成功显示了Git的版本信息,这表明Git已经被安装。 1. 使用Sourcetree SourceTree 是 Windows 和Mac OS X 下免费的 Git 和 Hg 客户端…

C++核心deque容器,stack容器,queue容器,list容器,set容器,pair ,map容器

3.deque容器 1.deque容器的基本概念 Vector容器是单向开口的连续内存空间&#xff0c;deque则是一种双向开口的连续线性空间。所谓的双向开口&#xff0c;意思是可以在头尾两端插入元素&#xff0c;但是在其头部操作效率奇差&#xff0c;无法被接受。 deque容器和vector容器最…

MongoDB索引详情

文章目录 MongoDB索引MongoDB索引数据结构WiredTiger数据文件在磁盘的存储结构 索引的分类索引设计原则索引操作创建索引查看索引删除索引 索引类型单键索引&#xff08;Single Field Indexes&#xff09;复合索引&#xff08;Compound Index&#xff09;多键索引&#xff08;M…

学成在线:采用XXL-JOB任务调度方案使用FFmpeg处理视频转码业务

分片技术方案 概述 XXL-JOB并不直接提供数据处理的功能&#xff0c;它只会给所有注册的执行器分配好分片序号&#xff0c;在向执行器下发任务调度的同时携带分片总数和当前分片序号等参数 设计作业分片方案保证多个执行器之间不会查询到重复的任务,保证任务不会重复执行 任…

机器学习-基础分类算法-KNN详解

KNN-k近邻算法 k-Nearest Neighbors 思想极度简单应用数学只是少效果好可以解释机器学习算法使用过程中的很多细节问题更完整的刻画机器学习应用的流程 创建简单测试用例 import numpy as np import matplotlib.pyplot as plt raw_data_X [[3.393533211, 2.331273381],[3.1…

Flutter实现轮播图功能

一、在pubspec.yaml中添加&#xff1a; dependencies:# 轮播图card_swiper: ^3.0.1card_swiper: ^3.0.1&#xff0c;要获取最新版本&#xff1a;https://pub-web.flutter-io.cn/packages/card_swiper/versions&#xff0c;这个里面有文档可以看&#xff0c;如下图&#xff1a;…

大模型ReAct智能体开发实战

哆啦A梦是很多人都熟悉的角色&#xff0c;包括我自己。 在成长过程中&#xff0c;我常常对他口袋里的许多小玩意感到惊讶&#xff0c;而且他知道何时使用它们。 随着大型语言模型 (LLM) 的发展趋势&#xff0c;你也可以构建一个具有相同行为方式的模型&#xff01; 我们将构建…

高中数学立体几何练习题3

用到的基础知识&#xff1a; 1. 2.

MATLAB计算多边形质心/矩心

前言&#xff1a;不规则四边形的中心 不规则四边形的出心有多种定义&#xff0c;以下是最常见的三种&#xff1a; 1.重心&#xff1a;重心是四边形内部所有顶点连线交点的平均位置。可以通过求解四个顶点坐标的平均值来找到重心。 2.质心&#xff1a;质心是四边形内部所有质点…

Python机器学习库(numpy库)

文章目录 Python机器学习库&#xff08;numpy库&#xff09;1. 数据的维度2. numpy基础知识2.1 numpy概述2.1 numpy概述2.1 numpy概述2.2 numpy库的引用 3. ndarray数组的创建3.1 N维数组对象ndarray3.2 创建ndarray数组3.2.1 使用Python列表、元组创建ndarray数组3.2.2 使用nu…

029 命令行传递参数

1.循环输出args字符串数组 public class D001 {public static void main(String[] args) {for (String arg : args) {System.out.println(arg);}} } 2.找打这个类的路径&#xff0c;打开cmd cmd C:\Users\Admin\IdeaProjects\JavaSE学习之路\scanner\src\com\yxm\demo 3. 编译…

Servlet+Ajax实现对数据的列表展示(极简入门)

目录 1.准备工作 1.数据库源&#xff08;这里以Mysql为例&#xff09; 2.映射实体类 3.模拟三层架构&#xff08;Dao、Service、Controller&#xff09; Dao接口 Dao实现 Service实现&#xff08;这里省略Service接口&#xff09; Controller层&#xff08;或叫Servlet层…