题目
给定一个由 0 和 1 组成的矩阵 matrix ,找出只包含 1 的最大矩形,并返回其面积。
注意:此题 matrix 输入格式为一维 01 字符串数组。
示例 1:
输入:matrix = [“10100”,“10111”,“11111”,“10010”]
输出:6
解释:最大矩形如上图所示。
示例 2:
输入:matrix = []
输出:0
示例 3:
输入:matrix = [“0”]
输出:0
示例 4:
输入:matrix = [“1”]
输出:1
示例 5:
输入:matrix = [“00”]
输出:0
提示:
rows == matrix.length
cols == matrix[0].length
0 <= row, cols <= 200
matrix[i][j] 为 ‘0’ 或 ‘1’
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/PLYXKQ
一、解题思路
我们首先计算出矩阵的每个元素的上边连续 1 的数量,使用二维数组 up 记录,其中 up[i][j] 为矩阵第 i 行第 j 列元素的上边连续 1 的数量。
如图:
这样就转化成了计算up数组每一行的最大矩形面积,最后比较每行的最大矩形面积得到最终答案。
最大矩形面积解题思路请看:
剑指 Offer II 039. 直方图最大矩形面积(单调栈)<必看>
也可转化成left数组,每个元素的左边连续 1 的数量,使用二维数组 left 记录,其中 left[i][j] 为矩阵第 i 行第 j 列元素的左边连续 1 的数量。
二、代码
class Solution {
//针对列,遍历每个i的高度,寻找低于其高度的边界
//相当于offer 039 的高度图逆时针转90度
public int maximalRectangle(String[] matrix) {
int n = matrix.length;
if(n==0) return 0;
int m = matrix[0].length();
//left数组表示当前left[i][j]左边有几个连续1
int[][] left = new int[n][m];
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(matrix[i].charAt(j)=='1')
left[i][j]= j==0? 1:left[i][j-1]+1;
}
}
int res =0;
for(int j=0;j<m;j++){
//当前列left的上下边界
int[] up =new int[n];
int[] down=new int[n];
Arrays.fill(down,n);
//单调栈 存放下标
Deque<Integer> eq = new LinkedList<>();
for(int i=0;i<n;i++){
//根据入栈出栈时机确定边界,所以每列中的每个数都会入栈
//所以首先明确出栈条件
while(!eq.isEmpty()&&left[eq.peek()][j]>=left[i][j]) down[eq.pop()]=i;
//入栈时,也就是栈空或者left[eq.peek()][j] < left[i][j] 那么eq.peek()就是i的上边界
up[i]= eq.isEmpty() ? -1:eq.peek();
eq.push(i);
}
for(int i=0;i<n;i++){
res=Math.max(res,(down[i]-up[i]-1)*left[i][j]);
}
}
return res;
}
//正向的
// public int maximalRectangle(String[] matrix) {
// int n = matrix.length;
// if(n==0) return 0;
// int m = matrix[0].length();
// int[][] up = new int[n][m];
// for(int i=0;i<n;i++){
// for(int j=0;j<m;j++){
// if(matrix[i].charAt(j)=='1')
// up[i][j] = i==0? 1:up[i-1][j]+1;
// }
// }
// int res =0;
// for(int i=0;i<n;i++){
// //当前行的左右边界
// int[] left=new int[m];
// int[] right = new int[m];
// Arrays.fill(right,m);
// Deque<Integer> eq= new LinkedList<>();
// for(int j=0;j<m;j++){
// //出栈条件
// while(!eq.isEmpty()&&up[i][eq.peek()]>=up[i][j]) right[eq.pop()]=j;
// left[j] = eq.isEmpty() ? -1:eq.peek();
// eq.push(j);
// }
// for(int j=0;j<m;j++){
// res= Math.max(res,(right[j]-left[j]-1)*up[i][j]);
// }
// }
// return res;
// }
}