leetcode
leetcode 51 ~ 100
最大矩形

最大矩形

难度:

标签:

题目描述

给定一个仅包含 01 、大小为 rows x cols 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。

 

示例 1:

输入:matrix = [["1","0","1","0","0"],["1","0","1","1","1"],["1","1","1","1","1"],["1","0","0","1","0"]]
输出:6
解释:最大矩形如上图所示。

示例 2:

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

示例 3:

输入:matrix = [["1"]]
输出:1

 

提示:

  • rows == matrix.length
  • cols == matrix[0].length
  • 1 <= row, cols <= 200
  • matrix[i][j]'0''1'

代码结果

运行时间: 74 ms, 内存: 22.3 MB


/*
 * 思路:
 * 1. 与普通的Java实现相似,只是在遍历数组和栈操作上使用Stream API。
 * 2. 使用Stream API将矩阵转换为高度数组,再计算每行的最大矩形面积。
 */
 
import java.util.Arrays;
import java.util.Stack;
 
public class MaximalRectangleStream {
    public int maximalRectangle(char[][] matrix) {
        if (matrix.length == 0) return 0;
        int[] heights = new int[matrix[0].length];
        return Arrays.stream(matrix)
            .mapToInt(row -> {
                IntStream.range(0, row.length).forEach(j -> {
                    heights[j] = (row[j] == '1') ? heights[j] + 1 : 0;
                });
                return largestRectangleArea(heights);
            })
            .max()
            .orElse(0);
    }
 
    private int largestRectangleArea(int[] heights) {
        Stack<Integer> stack = new Stack<>();
        int maxArea = 0;
        int index = 0;
        while (index < heights.length) {
            if (stack.isEmpty() || heights[index] >= heights[stack.peek()]) {
                stack.push(index);
                index++;
            } else {
                int height = heights[stack.pop()];
                int width = stack.isEmpty() ? index : index - stack.peek() - 1;
                maxArea = Math.max(maxArea, height * width);
            }
        }
        while (!stack.isEmpty()) {
            int height = heights[stack.pop()];
            int width = stack.isEmpty() ? index : index - stack.peek() - 1;
            maxArea = Math.max(maxArea, height * width);
        }
        return maxArea;
    }
}

解释

方法:

这个题解采用了单调栈的方法。主要思路是:逐行遍历矩阵,并维护一个高度数组 heights,heights[j] 表示第 j 列当前的连续 1 的高度。对于每一行,利用单调栈求解以当前行作为矩形底边的最大矩形面积。具体做法是,遍历高度数组,对于每个高度,利用单调栈找到左右两侧第一个小于它的位置,计算以当前高度为矩形的高、左右位置的差值为矩形的宽,求出面积并更新全局最大面积。

时间复杂度:

O(m * n)

空间复杂度:

O(n)

代码细节讲解

🦆
在单调栈的应用中,如何确保每次计算矩形面积时,栈中存储的都是还未处理的高度的下标?
在单调栈的应用中,我们确保栈内元素保持单调递增的顺序。当遇到一个新的高度`h`小于栈顶元素高度时,表示找到了栈顶元素的右边界。因此,我们不断弹出栈顶元素,直到栈顶元素的高度小于或等于当前高度`h`。这样操作保证了栈中仅保留那些还未找到右边界的高度的下标,且每个元素只会被处理一次,保证了高效性。
🦆
为什么在高度数组的首尾添加哨兵值0,这样的操作具体解决了哪些边界问题?
添加哨兵值0到高度数组的首尾主要是为了简化边界条件的处理。首先,在数组的开始添加0可以保证栈内总是有元素,方便处理左边界。在数组末尾添加0则是为了在最后一次循环中清空栈,保证所有的高度都能找到右边界并计算面积。这避免了在循环结束后还需额外的逻辑来清空栈中的元素。
🦆
在遍历矩阵更新高度数组时,直接将遇到的'0'的高度重置为0,这种做法是否有可能忽略掉某些潜在的最大矩形?
将遇到的'0'的高度重置为0是必要的,因为如果某个位置的值是'0',那么任何包含这个位置的矩形都不能被视为全1的矩形。这种做法实际上是在正确地更新每列的'连续1的高度'。它不会忽略潜在的最大矩形,因为每一行都会基于当前的高度数组求解最大矩形,确保考虑了所有可能的矩形。
🦆
函数`solve`中计算宽度为`i - k - 1`的原理是什么?这里的`i`和`k`分别指向哪些位置?
在函数`solve`中,`i`指的是当前考虑的高度的下标,而`k`是栈顶元素的下标,即当前高度左侧第一个小于当前高度的位置的下标。当从栈中弹出一个元素`j`时(即当前考虑的矩形的高度),栈顶的新元素`k`就成为了这个高度的新的左边界。因此,`i - k - 1`计算的是从左边界`k`到当前位置`i`之间的距离,减去1是因为左边界本身不包含在内,这样就得到了矩形的宽度。

相关问题

柱状图中最大的矩形

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。

求在该柱状图中,能够勾勒出来的矩形的最大面积。

 

示例 1:

输入:heights = [2,1,5,6,2,3]
输出:10
解释:最大的矩形为图中红色区域,面积为 10

示例 2:

输入: heights = [2,4]
输出: 4

 

提示:

  • 1 <= heights.length <=105
  • 0 <= heights[i] <= 104

最大正方形

在一个由 '0''1' 组成的二维矩阵内,找到只包含 '1' 的最大正方形,并返回其面积。

 

示例 1:

输入:matrix = [["1","0","1","0","0"],["1","0","1","1","1"],["1","1","1","1","1"],["1","0","0","1","0"]]
输出:4

示例 2:

输入:matrix = [["0","1"],["1","0"]]
输出:1

示例 3:

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

 

提示:

  • m == matrix.length
  • n == matrix[i].length
  • 1 <= m, n <= 300
  • matrix[i][j]'0''1'