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
import java.util.Stack;
class num85 {
public int maximalRectangle(char[][] matrix) {
int m = matrix.length;
if(m == 0) return 0;
int n = matrix[0].length;
int max = 0;
int[] height = new int[n+1];
height[n] = 0;
for(int i=0; i<m; i++){
for(int j=0; j<n; j++){
if(matrix[i][j] == '1'){
height[j] += 1;
}else{
height[j] = 0;
}
}
max = Math.max(max, largestRectangleArea(height));
}
return max;
}
// 使用局部峰值的方法
// public int largestRectangleArea(int[] height){
// int res = 0;
// for(int i=0; i<height.length; i++){
// if(i+1<height.length && height[i]<=height[i+1]) continue;
// int minH = height[i];
// for(int j=i; j>=0; j--){
// minH = Math.min(minH, height[j]);
// int temp = (i-j+1) * minH;
// res = Math.max(temp, res);
// }
// }
// return res;
// }
// 使用堆栈的方法
public int largestRectangleArea(int[] height){
int res = 0;
Stack<Integer> stack = new Stack<Integer>();
for(int i=0; i<height.length; ++i){
if(stack.empty() || height[stack.peek()] < height[i]){
stack.push(i);
}else{
int cur = stack.pop();
res = Math.max(res, height[cur] * (stack.empty()? i: i-stack.peek()-1));
--i;
}
}
return res;
}
public int largestRectangleArea(int[] height){
int res = 0;
Stack<Integer> stack = new Stack<Integer>();
for(int i=0; i<height.length; ++i){
while(!stack.empty()&&height[stack.peek()]>=height[i]){
int cur = stack.pop();
res = Math.max(res, height[cur] * (stack.empty()? i: i-stack.peek()-1));
}
stack.push(i);
}
return res;
}
public static void main(String[] args) {
char[][] matrix = {
{'1','0','1','0','0'},
{'1','0','1','1','1'},
{'1','1','1','1','1'},
{'1','0','0','1','0'}
};
num85 solution = new num85();
System.out.println(solution.maximalRectangle(matrix));
}
}
将该问题看做求直方图的最大面积的问题的变形形式,将每层都看做直方图的底层,然后求当前可表示成的直方图的最大矩形面积。
1、求以每层为底层的直方图高度
遍历该层的每一个元素,如果为0则将高度置为0,否则为上一层的高度加1
2、求直方图的最大矩形面积
(1)使用局部峰值的方法;首先找到局部峰值,然后根据峰值计算当前的最大面积。因为面积的值局限于直方图最矮的高度,如果有递增的直方图序列,不需要冗余计算峰值前面的面积,因为包括峰值的后面的矩形肯定大于前面的矩形面积。
eg:[2, 1, 5, 6, 2, 3]
对于1,5,6这样的递增序列,不需要重复计算[2, 1, 5]中的最大值,因为加上6之后的最大矩形肯定更大。
但是此种方法超时。
(2)使用堆栈的方法;此种方法使用堆栈维护一个局部的峰值,将递增的序列放入堆栈中,遇到小于当前的高度后就开始进行处理,处理的时候每次弹出一个栈中的宽度为1的最高元素进行计算,然后再弹出宽度为2的矮一些的元素进行计算,直到栈顶的元素的高度值小于当前i值。堆栈中存放高度的索引值。
stack: 0[2] 遇到1小于2,开始计算,得到最大值为2; 将栈中的元素弹出。
stack:1[1] , 2[5], 3[6], 遇到2小于6,开始求最大值,得出最大值为10,将栈中的2,3弹出。
stack: 1[1], 4[2] , 5[3], 开始求最大值,得出最大值为4。