类似于蓄水池问题,首先创造一个矩形,记录每一列上true的数量。
[
[1, 1, 0, 0, 1],
[0, 1, 0, 0, 1],
[0, 0, 1, 1, 1],
[0, 0, 1, 1, 1],
[0, 0, 0, 0, 1]
]
可转换为:
[
[1, 1, 0, 0, 1],
[0, 2, 0, 0, 2],
[0, 0, 1, 1, 3],
[0, 0, 2, 2, 4],
[0, 0, 0, 0, 5]
]
第一种方案:a[i][j]=min(a[i][j-1],matrix[i][k])×矩阵长度。 但是如果为递增的阶梯形时,会多算很多1. 因为a[i][j-1]不能代表以a[i][j-1]为右下脚的矩阵对高度。
第二种:记录每一行最小值和连续不为0的长度,然后和matrix[i][j]比较求最大面积。同样不可行,递增阶梯形时会出问题。
第三种方案:看来只能用Largest Rectangle in Histogram的方法,使用stack。维护一个stack,stack储存index,元素的高度递增。为什么是递增的?可以准确确定最小高度,及适用长度(从当前index到end)。递减也可以。但必须保证单调性。每次遇到递减时,为什么可以pop?因为遇到递减时,则代表遇到峰值,遇到峰值时,我们可以确定其包含的最大矩阵的右边界。其左边界也可以根据stack.peek确定。
如图为当前指针走到index=4时,出现递减情况,则第一张图是stack出栈,然后根据stack中前一个值以及index位置确定左右边界,根据stack中当前值确定高度。
第一张图:stack: 0,1,2. index=3 面积等于(3-1-1) * 5=5 如图绿色部分
第二张图:stack:0,1 index=3 面积为(3-0-1)*3=6 如图绿色部分
public class Solution {
/**
* @param matrix a boolean 2D matrix
* @return an integer
*/
public int maximalRectangle(boolean[][] s) {
int height = s.length;
if(height == 0) return 0;
int width = s[0].length;
if(width == 0) return 0;
int[][] matrix = new int[height][width];
for(int i = 0; i < height; i++) {
for(int j = 0; j < width; j++) {
if(i > 0)
matrix[i][j] = s[i][j] == true ? matrix[i - 1][j] + 1 : 0;
else
matrix[i][j] = s[i][j] == true ? 1 : 0;
}
}
int res = 0;
for(int i = 0; i < height; i++) {
res = Math.max(res, getSquare(i, matrix));
}
return res;
}
private int getSquare(int i, int[][] matrix) {
int res = 0;
Stack<Integer> stack = new Stack<Integer>();
for(int j = 0; j < matrix[0].length; j++) {
if(stack.isEmpty() || matrix[i][j] > matrix[i][stack.peek()]) {
stack.push(j);
} else {
int top = stack.peek();
while(matrix[i][top] >= matrix[i][j]) {
stack.pop();
int length = stack.isEmpty() ? j : j - stack.peek() - 1;
res = Math.max(res, matrix[i][top] * length);
if(stack.isEmpty()) {
break;
}
top = stack.peek();
}
stack.push(j);
}
}
while(!stack.isEmpty()) {
int top = stack.pop();
int length = stack.isEmpty() ? matrix[0].length : matrix[0].length - stack.peek() - 1;
res = Math.max(res, matrix[i][top] * length);
}
return res;
}
}