单调栈题目:最大矩形

题目

标题和出处

标题:最大矩形

出处:85. 最大矩形

难度

8 级

题目描述

要求

给定一个仅包含 0 \texttt{0} 0 1 \texttt{1} 1、大小为 rows × cols \texttt{rows} \times \texttt{cols} rows×cols 的二进制矩阵 matrix \texttt{matrix} matrix,找出只包含 1 \texttt{1} 1 的最大矩形,并返回其面积。

示例

示例 1:

示例 1

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

示例 2:

输入: matrix   =   [] \texttt{matrix = []} matrix = []
输出: 0 \texttt{0} 0

示例 3:

输入: matrix   =   [["0"]] \texttt{matrix = [["0"]]} matrix = [["0"]]
输出: 0 \texttt{0} 0

示例 4:

输入: matrix   =   [["1"]] \texttt{matrix = [["1"]]} matrix = [["1"]]
输出: 1 \texttt{1} 1

示例 5:

输入: matrix   =   [["0","0"]] \texttt{matrix = [["0","0"]]} matrix = [["0","0"]]
输出: 0 \texttt{0} 0

数据范围

  • rows = matrix.length \texttt{rows} = \texttt{matrix.length} rows=matrix.length
  • cols = matrix[0].length \texttt{cols} = \texttt{matrix[0].length} cols=matrix[0].length
  • 0 ≤ row,   cols ≤ 200 \texttt{0} \le \texttt{row, cols} \le \texttt{200} 0row, cols200
  • matrix[i][j] \texttt{matrix[i][j]} matrix[i][j] ‘0’ \texttt{`0'} ‘0’ ‘1’ \texttt{`1'} ‘1’

解法

思路和算法

只要记录矩阵中的每个元素 1 1 1 及其上边的连续 1 1 1 的数量,即可使用「柱状图中最大的矩形」的方法求解。具体而言,创建一个和 matrix \textit{matrix} matrix 相同大小的矩阵,新矩阵中的每个元素为 matrix \textit{matrix} matrix 中相同位置的元素及其上边的连续 1 1 1 的数量,特别地,对于 matrix \textit{matrix} matrix 中的元素 0 0 0,新矩阵中的对应元素是 0 0 0

示例 1 的 matrix \textit{matrix} matrix 如下:

1 0 1 0 0 1 0 1 1 1 1 1 1 1 1 1 0 0 1 0 \begin{matrix} 1 & 0 & 1 & 0 & 0 \\ 1 & 0 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & 1 \\ 1 & 0 & 0 & 1 & 0 \end{matrix} 11110010111001110110

对应的新矩阵如下:

1 0 1 0 0 2 0 2 1 1 3 1 3 2 2 4 0 0 3 0 \begin{matrix} 1 & 0 & 1 & 0 & 0 \\ 2 & 0 & 2 & 1 & 1 \\ 3 & 1 & 3 & 2 & 2 \\ 4 & 0 & 0 & 3 & 0 \end{matrix} 12340010123001230120

对于新矩阵中的每一行,其中的元素可以看成是以这一行为底的柱状图的每个柱子的高度。因此,在计算出新矩阵之后,遍历新矩阵的每一行,使用「柱状图中最大的矩形」的方法计算以这一行为底的最大矩形面积,遍历全部行之后即可得到矩阵中只包含 1 1 1 的最大矩形面积。

实现方面,并不需要事先计算出新矩阵,而是可以在遍历 matrix \textit{matrix} matrix 的过程中计算,每次计算一行。

具体做法是,创建长度为 cols \textit{cols} cols 的数组 heights \textit{heights} heights,初始时 heights \textit{heights} heights 的每个元素都是 0 0 0,依次遍历 matrix \textit{matrix} matrix 的每一行,进行如下操作:

  1. 对于 matrix \textit{matrix} matrix 的当前行的每个元素,如果该元素是 0 0 0 则将 heights \textit{heights} heights 的对应元素设为 0 0 0,如果该元素是 1 1 1 则将 heights \textit{heights} heights 的对应元素加 1 1 1,此时 heights \textit{heights} heights 的每个元素为 matrix \textit{matrix} matrix 中的对应位置的元素及其上边的连续 1 1 1 的数量;

  2. 遍历完 matrix \textit{matrix} matrix 的当前行之后,根据 heights \textit{heights} heights 计算以当前行为底的最大矩形面积,并更新结果。

遍历结束之后返回结果。

代码

class Solution {
    public int maximalRectangle(char[][] matrix) {
        if (matrix.length == 0 || matrix[0].length == 0) {
            return 0;
        }
        int maxArea = 0;
        int rows = matrix.length, cols = matrix[0].length;
        int[] heights = new int[cols];
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                if (matrix[i][j] == '0') {
                    heights[j] = 0;
                } else {
                    heights[j]++;
                }
            }
            maxArea = Math.max(maxArea, getMaxArea(heights));
        }
        return maxArea;
    }

    public int getMaxArea(int[] heights) {
        int length = heights.length;
        int[] left = new int[length];
        int[] right = new int[length];
        Arrays.fill(left, -1);
        Arrays.fill(right, length);
        Deque<Integer> stack = new ArrayDeque<Integer>();
        for (int i = 0; i < length; i++) {
            int height = heights[i];
            while (!stack.isEmpty() && heights[stack.peek()] >= height) {
                right[stack.pop()] = i;
            }
            if (!stack.isEmpty()) {
                left[i] = stack.peek();
            }
            stack.push(i);
        }
        int area = 0;
        for (int i = 0; i < length; i++) {
            area = Math.max(area, (right[i] - left[i] - 1) * heights[i]);
        }
        return area;
    }
}

复杂度分析

  • 时间复杂度: O ( rows × cols ) O(\textit{rows} \times \textit{cols}) O(rows×cols),其中 rows \textit{rows} rows cols \textit{cols} cols 分别是矩阵 matrix \textit{matrix} matrix 的行数和列数。需要遍历矩阵 matrix \textit{matrix} matrix 的每一行,行数是 rows \textit{rows} rows,对于每一行,计算 heights \textit{heights} heights 和计算以这一行为底的最大矩形面积的时间复杂度都是 O ( cols ) O(\textit{cols}) O(cols),因此总时间复杂度是 O ( rows × cols ) O(\textit{rows} \times \textit{cols}) O(rows×cols)

  • 空间复杂度: O ( cols ) O(\textit{cols}) O(cols),其中 cols \textit{cols} cols 是矩阵 matrix \textit{matrix} matrix 的列数。数组 heights \textit{heights} heights 的长度是 cols \textit{cols} cols,计算以每一行为底的最大矩形面积的空间复杂度是 O ( cols ) O(\textit{cols}) O(cols),因此总空间复杂度是 O ( cols ) O(\textit{cols}) O(cols)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

伟大的车尔尼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值