问题
Given a 2D binary matrix filled with 0’s and 1’s, find the largest rectangle containing only 1’s and return its area.
Example:
Input:
[
[“1”,“0”,“1”,“0”,“0”],
[“1”,“0”,“1”,“1”,“1”],
[“1”,“1”,“1”,“1”,“1”],
[“1”,“0”,“0”,“1”,“0”]
]
Output: 6
分析
首先分享一个傻叉思路,当然这个思路由于超时而告终。
暴力动态规划:
遍历二维矩阵中的每一个元素;针对该位置,向四个方向进行矩形扩展;扩展过程中,记录当前可构成矩形的行和列的范围,即rowstart,rowend,colstart和colend;
递归终止条件:扩展超出matrix边界,或不能组成矩形。
以当前构成矩形的范围为rowstart,rowend,colstart和colend,向上扩展为例:rowstart=rostart-1;
1)若rowstart<0,end;
2)若matrix在colstart——colend范围内,存在元素!=‘1’,表示该次扩展尝试失败,end。
最后比较四个方向扩展的面积,取最大者返回。
时间复杂度:O(m2n2);(啊不会分析,可能比这个高)
空间复杂度:emmm
基于最大矩形面积:
https://leetcode.com/problems/maximal-rectangle/discuss/29055/My-java-solution-based-on-Maximum-Rectangle-in-Histogram-with-explanation
对于矩阵matrix,我们一行行的来看,截止到当前行,能够组成的最大矩形。
(啊不知道怎么解释)
row[]数组:记录截止到当前行,各列的最大高度。
遍历时的规则是:如果matrix[i][j]==‘1’(注意是字符矩阵),则row[j]=row[j]+1;(即在之前的基础上增加)否则,row[j]=0;
这个规则的原因是:记录截止到当前行,各列的1组成的最大高度。
以问题中的matrix为例,遍历所有行之后,一次得到的row为:
[“1”,“0”,“1”,“0”,“0”], --> [1,0,1,0,0], 相当于组成了高度为1,0,1,0,0的一个矩形序列
[“1”,“0”,“1”,“1”,“1”], --> [2,0,2,1,1] 相当于组成了高度为2,0,2,1,1的一个矩形序列
[“1”,“1”,“1”,“1”,“1”], --> [3,1,3,2,2]
[“1”,“0”,“0”,“1”,“0”] --> [4,0,1,3,0]
代码
暴力动态规划
public int maximalRectangle(char[][] matrix) {
int ans=0;
int curr=1;
if(matrix==null||matrix.length==0) return 0;
int rowNum=matrix.length;
int colNum=matrix[0].length;
for(int i=0;i<rowNum;i++){
for(int j=0;j<colNum;j++){
if(matrix[i][j]=='0') continue;
curr=getResult(matrix,i,i,j,j,curr);
if(curr>ans) ans=curr;
}
}
return ans;
}
private int getResult(char[][] matrix, int rowstart, int rowend, int colstart, int colend, int curr) {
//终止条件:
if(rowstart<0||colstart<0||rowend>=matrix.length||colend>=matrix[0].length) return -1;
//如果无法扩展,return
for(int i=colstart;i<=colend;i++){
if(matrix[rowstart][i]=='0'||matrix[rowend][i]=='0') return -1;
}
for(int i=rowstart;i<=rowend;i++){
if(matrix[i][colstart]=='0'||matrix[i][colend]=='0') return -1;
}
//计算当前矩形面积
curr=(rowend-rowstart+1)*(colend-colstart+1);
//当前矩形进行拓展
int a=getResult(matrix,rowstart-1,rowend,colstart,colend,curr);
int b=getResult(matrix,rowstart,rowend+1,colstart,colend,curr);
int c=getResult(matrix,rowstart,rowend,colstart-1,colend,curr);
int d=getResult(matrix,rowstart,rowend,colstart,colend+1,curr);
if(a!=-1&&a>=b&&a>=c&&a>=d) return a;
if(b!=-1&&b>=a&&b>=c&&b>=d) return b;
if(c!=-1&&c>=a&&c>=b&&c>=d) return c;
if(d!=-1&&d>=a&&d>=b&&d>=c) return d;
return curr;
}
基于最大矩形面积:
public int maximalRectangle(char[][] matrix) {
if (matrix == null || matrix.length == 0)
return 0;
int[] row = new int[matrix[0].length];// 记录截止到当前行的列高
int area = 0, currArea = 0;// 记录最大面积和当前最大面积
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[0].length; j++) {
if (i == 0)
row[j] = matrix[i][j] == '1' ? 1 : 0;
else {
row[j] = matrix[i][j] == '1' ? row[j] + 1 : 0;
}
}
// 计算截止到当前行的最大矩形
currArea = getMax(row);
area = currArea > area ? currArea : area;
}
return area;
}
private int getMax(int[] height) {
// 来自:https://leetcode.com/problems/largest-rectangle-in-histogram/discuss/28900/O(n)-stack-based-JAVA-solution
int len = height.length;
Stack<Integer> s = new Stack<Integer>();
int maxArea = 0;
for (int i = 0; i <= len; i++) {
int h = (i == len ? 0 : height[i]);
if (s.isEmpty() || h >= height[s.peek()]) {
s.push(i);
} else {
int tp = s.pop();
maxArea = Math.max(maxArea, height[tp] * (s.isEmpty() ? i : i - 1 - s.peek()));
i--;
}
}
return maxArea;
}