题目
Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing all ones and return its area.
分析
这题最直接的就是O(m^2 * n)的遍历(解法1),从左到右(或者从右到左)得到每个节点左(右)方连续的‘1’(包括自己)的个数。同时,从下到上(或从上到下)计算节点下方(上方)所能构成的矩形的最大值。
这题与Largest Rectangle in Histogram联系紧密,从上到下(或从下到上)得到每个节点上(下)方连续'1'(包括自己)的个数。则要得到最大矩形,就是在每一行里进行一次Largest Rectangle in Histogram,这样得到了解法2。虽然这样复杂度降到了O(m * n),但是从LeetCode测试结果上看,解法1还更快些,可能是解法1运气好的时候剪枝比较多。
还有一种非常高大上的解法(解法3),参考http://hi.baidu.com/mzry1992/item/030f9740e0475ef7dc0f6cba,这个是O(m * n)时间复杂度,O(n)空间复杂度。先前两种空间复杂度都是O(m * n)。
解法1
public class MaximalRectangle {
public int maximalRectangle(char[][] matrix) {
if (matrix == null || matrix.length == 0) {
return 0;
}
int M = matrix.length;
int N = matrix[0].length;
int max = 0;
// init
int[][] dp = new int[M + 1][N + 1];
// dp
for (int i = M - 1; i >= 0; --i) {
for (int j = N - 1; j >= 0; --j) {
if (matrix[i][j] == '1') {
dp[i][j] = dp[i][j + 1] + 1;
int min = dp[i][j];
int count = 1;
int tempMax = dp[i][j];
while (dp[i + count][j] != 0) {
++count;
min = Math.min(dp[i + count][j], min);
tempMax = Math.max(min * count, tempMax);
}
max = Math.max(max, tempMax);
}
}
}
return max;
}
}
解法2
public class MaximalRectangle {
public int maximalRectangle(char[][] matrix) {
if (matrix == null || matrix.length == 0) {
return 0;
}
int M = matrix.length;
int N = matrix[0].length;
int max = 0;
int[][] height = new int[M + 1][N];
for (int i = 1; i <= M; ++i) {
Stack
stack = new Stack
(); for (int j = 0; j < N; ++j) { if (matrix[i - 1][j] == '1') { height[i][j] = height[i - 1][j] + 1; } if (stack.isEmpty() || height[i][stack.peek()] <= height[i][j]) { stack.push(j); } else { int index = stack.pop(); int area = height[i][index] * (stack.isEmpty() j : (j - stack.peek() - 1)); max = Math.max(max, area); --j; } } while (!stack.isEmpty()) { int index = stack.pop(); int area = height[i][index] * (stack.isEmpty() N : (N - stack.peek() - 1)); max = Math.max(max, area); } } return max; } }
解法3
public class MaximalRectangle {
public int maximalRectangle(char[][] matrix) {
if (matrix == null || matrix.length == 0) {
return 0;
}
int M = matrix.length;
int N = matrix[0].length;
int[] H = new int[N];
int[] L = new int[N];
int[] R = new int[N];
for (int i = 0; i < N; ++i) {
R[i] = N;
}
int ret = 0;
for (int i = 0; i < M; ++i) {
int left = 0, right = N;
// calculate L(i, j) from left to right
for (int j = 0; j < N; ++j) {
if (matrix[i][j] == '1') {
++H[j];
L[j] = Math.max(L[j], left);
} else {
left = j + 1;
H[j] = 0;
L[j] = 0;
R[j] = N;
}
}
// calculate R(i, j) from right to left
for (int j = N - 1; j >= 0; --j) {
if (matrix[i][j] == '1') {
R[j] = Math.min(R[j], right);
ret = Math.max(ret, H[j] * (R[j] - L[j]));
} else {
right = j;
}
}
}
return ret;
}
}