文章目录
- 最大矩形
- ⛅前言
- 🔒题目
- 🔑题解
最大矩形
⛅前言
大家好,我是知识汲取者,欢迎来到我的LeetCode热题100刷题专栏!
精选 100 道力扣(LeetCode)上最热门的题目,适合初识算法与数据结构的新手和想要在短时间内高效提升的人,熟练掌握这 100 道题,你就已经具备了在代码世界通行的基本能力。在此专栏中,我们将会涵盖各种类型的算法题目,包括但不限于数组、链表、树、字典树、图、排序、搜索、动态规划等等,并会提供详细的解题思路以及Java代码实现。如果你也想刷题,不断提升自己,就请加入我们吧!QQ群号:827302436。我们共同监督打卡,一起学习,一起进步。
LeetCode热题100专栏🚀:LeetCode热题100
Gitee地址📁:知识汲取者 (aghp) - Gitee.com
题目来源📢:LeetCode 热题 100 - 学习计划 - 力扣(LeetCode)全球极客挚爱的技术成长平台
PS:作者水平有限,如有错误或描述不当的地方,恳请及时告诉作者,作者将不胜感激
🔒题目
原题链接:85.最大矩形
🔑题解
-
解法一:往下扩展(以当前节点作为矩形的右上角)
先构建一个sum数组(这个很重要),
sum[i][j]
表示第i行第j列的节点,从当前节点往左出现连续1的长度(也就是记录当前节点为矩形右上角的最大宽度),前言万语抵不过一张图,看完下面几张图我相信你能够明白的①如下是matrix数组:
②构建sum数组(从左往右对出现连续1的节点进行自增操作):
③以当前节点为矩形的右上角,计算节点能构成矩形的最大面积
例如,遍历第一个节点时,先以自生高度,然后往下枚举,高度加一
……
例如,枚举第10个节点时,第一层的矩形直接是3,往下扩展,此时第二层的宽是5,第一层的宽是3,以最短的宽为准,所以此时矩形的面积是6,第三层的宽是0,所以第三层不能构成一个矩形,综上,节点10能组成矩形的最大面积是6
/** * @author ghp * @title */ class Solution { public int maximalRectangle(char[][] matrix) { int m = matrix.length; int n = matrix[0].length; // 构建sum数组 int[][] sum = new int[m][n]; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { if (matrix[i][j] == '1') { if (j == 0) { sum[i][j] = 1; } else { sum[i][j] += sum[i][j - 1] + 1; } } else { sum[i][j] = 0; } } } int ans = 0; // 枚举每一个节点 for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { int width = sum[i][j]; // 枚举当前节点下的所有行 for (int k = i; k < m; k++) { // 当k=i时,是当前层的高度,所以需要+1 int height = k - i + 1; // 选所有行中的最小宽度作为当前矩形的宽度 width = Math.min(width, sum[k][j]); // 更新最大矩形的面积 ans = Math.max(ans, height * width); } } } return ans; } }
复杂度分析:
- 时间复杂度: O ( n 2 ) O(n^2) O(n2)
- 空间复杂度: O ( m ∗ n ) O(m*n) O(m∗n)
其中 n n n 为数组中元素的个数
-
解法二:往上扩展(以当前节点作为矩形的右下角)
解法一,自上而下枚举,节点要枚举两遍,第一遍枚举构建sum数组,第二遍枚举计算节点能构成矩形的最大面积。我们可以换一种思路,自下而上枚举,在枚举节点构建sum数组的同时,还计算当前节点能构成矩形的最大面积,这样就能够省掉一遍枚举,虽然时间复杂度没有减小,但是节约了时间😄
①枚举第1个节点,得到矩形的最大面积是1:
……
②枚举10个节点,此时第10个节点的左边和上边的节点的和都计算了:
遍历第10个节点所在当前层时,矩形的宽度是3,此时矩形的面积是3,往上扩展,上一层的宽度是0,所以此时矩形的面积是0。所以此时第10个节点能够成矩形的最大面积是3
③枚举第15个节点:
当前层构成矩形的最大面积是5,往上扩展后,此时最小宽度变成了3,高度变成了2,构成矩形的最大面积是6,继续往上扩展……
最终可以得到第15个节点能够构成矩形的最大面积是6
/** * @author ghp * @title */ class Solution { public int maximalRectangle(char[][] matrix) { int m = matrix.length; int n = matrix[0].length; int[][] sum = new int[m][n]; int ans = 0; for (int i = 0; i < m; i++) { // 构建sum数组 for (int j = 0; j < n; j++) { if (matrix[i][j] == '1') { if (j == 0) { sum[i][j] = 1; } else { sum[i][j] += sum[i][j - 1] + 1; } } else { sum[i][j] = 0; } int width = sum[i][j]; // 以当前节点为矩形的右下角,往上枚举 for (int k = i; k >= 0; k--) { int height = i - k + 1; // 选所有行中的最小宽度作为当前矩形的宽度 width = Math.min(width, sum[k][j]); // 更新最大矩形的面积 ans = Math.max(ans, height * width); } } } return ans; } }
复杂度分析:
- 时间复杂度: O ( n 2 ) O(n^2) O(n2)
- 空间复杂度: O ( m ∗ n ) O(m*n) O(m∗n)
其中 n n n 为数组中元素的个数
-
解法三:思维转换
我们要求一个 m ∗ n m*n m∗n的二维数组中,连续1组成的一个最大矩形面积,如果直接来暴力枚举,可能时间复杂度很高,我们可以换一种思路,把每一列连续的1看着一个柱子,我们只需要求相邻柱子构成的最大面积,这样恒容易就想到了84题
PS:我是一路刷LeetCode热题100遇到这题的,并且是根据题号一路刷过来的,所以刚好(●’◡’●),但是这个思路我并没有想到🤣我还有待继续努力(ง •_•)ง
温馨提示:如果你没有做过84题,建议先把84题写完再来写这一题,可能豁然开朗
关于这题的具体思路,我相信看完下面这几张图,你应该会有所了解的:
①一层一层对二维数组matrix纵向求和
②得到sum数组(从上至下对连续出现1的节点进行自增操作):
③此时我们可以,把每一层(也就是每一行)看作一个地平线,这样就可以计算每一层相邻柱子能构成最大矩形的面积,当然还需要单独使用一个变量来记录当前全局最大矩形的面积
第一层:最大面积是4
第二层:最大面积是6
第三层……
最后通过迭代计算,可以得出martix数组中有连续1构成的矩形的最大面积是6,下面是题解代码:
import java.util.ArrayDeque; import java.util.Deque; /** * @author ghp * @title */ class Solution { public int maximalRectangle(char[][] matrix) { int m = matrix.length; int n = matrix[0].length; // 构建sum数组 int[][] sum = new int[m + 1][n + 1]; for (int i = 1; i <= m; i++) { for (int j = 1; j <= n; j++) { sum[i][j] = matrix[i - 1][j - 1] == '0' ? 0 : sum[i - 1][j] + 1; } } // 遍历每一层的柱子,更新max int max = Integer.MIN_VALUE; for (int i = 1; i <= m; i++) { // 这里就可以直接调用 【84.柱状图中最大的矩形】 的方法了 max = Math.max(max, largestRectangleArea(sum[i])); } return max; } public int largestRectangleArea(int[] heights) { // 创建一个临时数组,前0用于计算第一个柱子的面积,后一个0用于强制出栈(这一步超级重要) int[] tempArr = new int[heights.length + 2]; for (int i = 1; i < heights.length + 1; i++) { tempArr[i] = heights[i - 1]; } // 递增栈(栈中存储柱子的索引号,栈中的柱子的高度严格递增) Deque<Integer> stack = new ArrayDeque<>(); int ans = 0; // 枚举当前层所有的柱子 for (int i = 0; i < tempArr.length; i++) { while (!stack.isEmpty() && tempArr[i] < tempArr[stack.peek()]) { // 当前柱子比上一个柱子的高度要矮,不符合单调递增栈的要求,停止入栈 // 计算最上一个柱子能构成最大矩形的面积 int index = stack.poll(); ans = Math.max(ans, (i - stack.peek() - 1) * tempArr[index]); } stack.push(i); } return ans; } }
复杂度分析:
- 时间复杂度: O ( n ∗ m ) O(n*m) O(n∗m)
- 空间复杂度: O ( n ∗ m ) O(n*m) O(n∗m)
其中 n n n 为matrix数组的列, m m m为matrix数组的行
PS:这里关于【84.柱状图中最大的矩形】的题解,可以参考这篇文章
【LeetCode热题100】打卡第25天:柱状图中最大的矩形_知识汲取者的博客-CSDN博客