Leetcode 85. 最大矩形

这篇具有很好参考价值的文章主要介绍了Leetcode 85. 最大矩形。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

题目信息

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

题目理解

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

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

以示例1为例:

Leetcode 85. 最大矩形,leetcode,算法,职场和发展

如果将每一行的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--]];
                    // 此处如果发现栈里仅存在唯一一个元素,则说明之前不存在其他元素,亦或者是所有其他元素所对应的高度均超过height,所以我们可以大胆假设leftIndex = -1
                    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),我们需要一个临时数组存储每行的列高度,以及栈。文章来源地址https://www.toymoban.com/news/detail-830610.html

到了这里,关于Leetcode 85. 最大矩形的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 算法leetcode|84. 柱状图中最大的矩形(rust重拳出击)

    给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。 求在该柱状图中,能够勾勒出来的矩形的最大面积。 1 = heights.length =10 5 0 = heights[i] = 10 4 面对这道算法题目,二当家的再次陷入了沉思。 眼睛一看似乎有思路,但是一动手就容易不知

    2024年02月08日
    浏览(32)
  • 【leetcode热题100】接雨水、直方图最大矩形面积、矩阵中最大的矩形

    题目链接 题目描述: 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 示例 1: 输入:height = [0,1,0,2,1,0,1,3,2,1,2,1] 输出:6 解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝

    2024年02月03日
    浏览(42)
  • LeetCode 84. 柱状图中最大的矩形

    84. 柱状图中最大的矩形 给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。 求在该柱状图中,能够勾勒出来的矩形的最大面积。 示例 1: 输入: heights = [2,1,5,6,2,3] 输出: 10 解释: 最大的矩形为图中红色区域,面积为 10 示例 2: 输入

    2024年02月03日
    浏览(25)
  • 【Leetcode -485.最大连续1的个数 -492.构造矩形】

    题目:给定一个二进制数组 nums , 计算其中最大连续 1 的个数。 示例 1: 输入:nums = [1, 1, 0, 1, 1, 1] 输出:3 解释:开头的两位和最后的三位都是连续 1 ,所以最大连续 1 的个数是 3. 示例 2: 输入:nums = [1, 0, 1, 1, 0, 1] 输出:2 思路是遍历一次数组,如果是1就使用变量count累加

    2024年02月05日
    浏览(32)
  • LeetCode热题HOT100:76. 最小覆盖子串,84.柱状图中最大的矩形、96. 不同的二叉搜索树

    题目 :给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。 注意: 对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。 如果 s 中存在这样的子串,我们保

    2023年04月19日
    浏览(31)
  • 算法leetcode|53. 最大子数组和(rust重拳出击)

    给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 子数组 是数组中的一个连续部分。 1 = nums.length = 10 5 -10 4 = nums[i] = 10 4 面对这道算法题目,二当家的再次陷入了沉思。 刚开始以为要暴力破解,双循环什么的,但

    2024年02月08日
    浏览(34)
  • 【算法与数据结构】654、LeetCode最大二叉树

    所有的LeetCode题解索引,可以看这篇文章——【算法和数据结构】LeetCode题解。    思路分析 :【算法与数据结构】106、LeetCode从中序与后序遍历序列构造二叉树这两道题有些类似,相关代码可以互相参考,本题明示了要用递归来做,那么递归三要素不可缺少: 输入参数和返

    2024年02月09日
    浏览(34)
  • 【算法|动态规划No.12】leetcode152. 乘积最大子数组

    个人主页:兜里有颗棉花糖 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 🍔本专栏旨在提高自己算法能力的同时,记录一下自己的学习过程,希望对大家有所帮助 🍓希望我们一起努力、成长,共同进步。

    2024年02月08日
    浏览(34)
  • LeetCode算法递归类—二叉树中的最大路径和

    目录 124. 二叉树中的最大路径和 - 力扣(LeetCode) 题解: 代码: 运行结果: 二叉树中的  路径  被定义为一条节点序列,序列中每对相邻节点之间都存在一条边。同一个节点在一条路径序列中  至多出现一次  。该路径  至少包含一个  节点,且不一定经过根节点。 路径和

    2024年02月12日
    浏览(27)
  • 【贪心算法】【中位贪心】LeetCode:100123.执行操作使频率分数最大

    双指针 C++算法:前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 贪心算法 给你一个下标从 0 开始的整数数组 nums 和一个整数 k 。 你可以对数组执行 至多 k 次操作: 从数组中选择一个下标 i ,将 nums[i] 增加 或者 减少 1 。 最终数组的频率分数定义为数组

    2024年02月04日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包