一、题目
给定一个仅包含 0
和 1
、大小为 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
示例 3:
输入:matrix = [["0","0"]]
输出:0
提示:
- rows == matrix.length
- cols == matrix[0].length
- 1 <= row, cols <= 200
- matrix[i][j] 为 '0' 或 '1'
二、代码
class Solution {
public int maximalRectangle(char[][] matrix) {
// 过滤无效参数
if (matrix.length == 0 || matrix == null || matrix[0].length == 0) {
return 0;
}
// 记录矩阵的行数和列数
int rowLen = matrix.length;
int colLen = matrix[0].length;
// 这个是用来记录每一行的所有直方图的高度
int[] heights = new int[colLen];
// 记录面积最大值(这里也就相当于包含1的个数)
int max = Integer.MIN_VALUE;
// 从第一层开始向下遍历,以每一层为地基,看能像上扩张多高。每遍历一层时,此时heights数组记录的就是上一层的直方图高度
// 如果当前这一层的值为1,那么就可以直接累加上一层对应位置的直方图高度,完成扩张
// 如果当前这一层的值为0,那么就没办法向上扩张了,就需要从0继续开始,更新heights数组对应位置的值为0
for (int i = 0; i < rowLen; i++) {
for (int j = 0; j < colLen; j++) {
// 如果当前这一层这个位置为0,就没办法接着上一层的直方图高度进行扩张了,需要重新开始记录直方图高度,将heights对应位置设置为0
if (matrix[i][j] != '0') {
heights[j] += (matrix[i][j] - '0');
} else {
heights[j] = 0;
}
}
// 每次遍历完,heights就是存储的当前这一层的直方图向上扩张的最大高度
// 这是就将这道题转换成了LeeyCode 84题求直方图中最大的矩形面积的问题了,只需要去看每一个直方图左右最大能扩多少,这里直接用这道题的求解代码,就能返回出来当前这一层的直方图中存在的最大矩形面积(利用单调栈求解)
// 然后取比较每一层的值,取最大值返回即可
max = Math.max(max, largestRectangleArea(heights));
}
// 返回最大面积(包含1个数最多的矩形)
return max;
}
public int largestRectangleArea(int[] heights) {
// 过滤无效参数
if (heights == null || heights.length == 0) {
return 0;
}
int n = heights.length;
// 创建单调栈
int[] stack = new int [n];
int top = -1;
int max = Integer.MIN_VALUE;
// 遍历数组,将每个数组添加进单调栈中
// 找到每个位置左右能扩大的最大范围,就是距离当前位置的长方形最近的并且高度小于它的长方形,在这两个高度小于它的长方形之间的全部长方形,都是可以扩张到形成大长方形的
for (int i = 0; i < n; i++) {
while (top != -1 && heights[stack[top]] >= heights[i]) {
int index = stack[top--];
// 形成的长方形高度都是固定的,都是heights[index],也就是从栈中弹出的高度
max = Math.max(max, top == -1 ? heights[index] * i : heights[index] * (i - stack[top] - 1));
}
stack[++top] = i;
}
// 单独处理单调栈中剩下的长方形
while (top != -1) {
int index = stack[top--];
max = Math.max(max, top == -1 ? heights[index] * n : heights[index] * (n - stack[top] - 1));
}
return max;
}
}
三、解题思路
以每一行为地基,看向上最大能扩张多高的直方图。
经过遍历这四行,其实在遍历过程中就能把每一行的直方图高度给找出来,然后其实就是去看每一行的直方图向左右扩张最多是多少。所以在找每一行的直方图时,再加上上一题的那个利用单调栈找每一行的直方图向左右扩张的面积最大值是多少。这里是求1的个数,其实就是求面积大小,这一部分可以直接复用上一题的代码。从每一行的直方图左右扩张最大面积中找到最大的那一个面积就是这道题最终的答案。