You can maintain a row length of Integer array H recorded its height of '1's, and scan and update row by row to find out the largest rectangle of each row.
For each row, if matrix[row][i] == '1'. H[i] +=1, or reset the H[i] to zero.
and accroding the algorithm of [Largest Rectangle in Histogram], to update the maximum area.
class Solution {
public int maximalRectangle(char[][] matrix) {
int rLen = matrix.length, cLen = rLen == 0 ? 0 : matrix[0].length, max = 0;
int[] h = new int[cLen+1];
for (int row = 0; row < rLen; row++) {
Stack<Integer> s = new Stack<Integer>();
s.push(-1);
for (int i = 0; i <= cLen ;i++) {
if(i < cLen && matrix[row][i] == '1')
h[i] += 1;
else h[i] = 0;
while(s.peek() != -1 && h[i] < h[s.peek()]) {
int height = h[s.pop()];
int width = i - s.peek() - 1;
max = Math.max(max, height * width);
}
s.push(i);
}
}
return max;
}
}
class Solution {
public int maximalRectangle(char[][] matrix) {
if(matrix.length==0) return 0;
int[][] dp = new int[matrix.length][matrix[0].length];
for (int i = 0; i < dp.length; i++) {
for (int j = 0; j < dp[0].length; j++) {
dp[i][j] = matrix[i][j]-'0';
if (dp[i][j] > 0 && i>0) dp[i][j] += dp[i - 1][j];
}
}
int max = 0;
for (int[] a : dp) max=Math.max(largestRectangleArea(a), max);
return max;
}
// copied "Largest Rectangle in Histogram" solution
public int largestRectangleArea(int[] a) {
LinkedList<Integer> stack = new LinkedList<>();
int max = 0;
for (int i = 0; i <= a.length; i++) {
while (!stack.isEmpty() && (i == a.length || a[stack.peek()] > a[i])) {
int height = a[stack.pop()];
int width = (!stack.isEmpty()) ? i - stack.peek() - 1 : i;
max = Math.max(max, height * width);
}
stack.push(i);
}
return max;
}
}
The DP solution proceeds row by row, starting from the first row. Let the maximal rectangle area at row i and column j be computed by [right(i,j) - left(i,j)]*height(i,j).
All the 3 variables left, right, and height can be determined by the information from previous row, and also information from the current row. So it can be regarded as a DP solution. The transition equations are:
left(i,j) = max(left(i-1,j), cur_left), cur_left can be determined from the current row
right(i,j) = min(right(i-1,j), cur_right), cur_right can be determined from the current row
height(i,j) = height(i-1,j) + 1, if matrix[i][j]=='1';
/* we start from the first row, and move downward;
* height[i] record the current number of countinous '1' in column i;
* left[i] record the left most index j which satisfies that for any index k from j to i, height[k] >= height[i];
* right[i] record the right most index j which satifies that for any index k from i to j, height[k] >= height[i];
* by understanding the definition, we can easily figure out we need to update maxArea with value (height[i] * (right[i] - left[i] + 1));
*
* Then the question is how to update the array of height, left, and right
* =================================
* for updating height, it is easy
* for (int j = 0; j < n; j++) {
* if (matrix[i][j] == '1') height[j]++;
* else height[j] = 0;
* }
* =============================================================================
* It is a little bit tricky for initializing and updating left and right array
* for initialization:
* we know initially, height array contains all 0, so according to the definition of left and right array, left array should contains all 0, and right array should contain all n - 1
* for updating left and right, it is kind of tricky to understand...
* ==============================================================
* Here is the code for updating left array, we scan from left to right
* int lB = 0; //lB is indicating the left boundry for the current row of the matrix (for cells with char "1"), not the height array...
* for (int j = 0; j < n; j++) {
* if (matrix[i][j] == '1') {
* left[j] = Math.max(left[j], lB); // this means the current boundry should satisfy two conditions: within the boundry of the previous height array, and within the boundry of the current row...
* } else {
* left[j] = 0; // when matrix[i][j] = 0, height[j] will get update to 0, so left[j] becomes 0, since all height in between 0 - j satisfies the condition of height[k] >= height[j];
* lB = j + 1; //and since current position is '0', so the left most boundry for next "1" cell is at least j + 1;
* }
* }
* ==============================================================
* the idea for updating the right boundary is similar, we just need to iterate from right to left
* int rB = n - 1;
* for (int j = n - 1; j >= 0; j--) {
* if (matrix[i][j] == '1') {
* right[j] = Math.min(right[j], rB);
* } else {
* right[j] = n - 1;
* rB = j - 1;
* }
*/
class Solution {
public int maximalRectangle(char[][] matrix) {
if (matrix == null || matrix.length == 0 || matrix[0] == null || matrix[0].length == 0) return 0;
int m = matrix.length, n = matrix[0].length, maxArea = 0;
int[] left = new int[n];
int[] right = new int[n];
int[] height = new int[n];
Arrays.fill(right, n - 1);
for (int i = 0; i < m; i++) {
int rB = n - 1;
for (int j = n - 1; j >= 0; j--) {
if (matrix[i][j] == '1') {
right[j] = Math.min(right[j], rB);
} else {
right[j] = n - 1;
rB = j - 1;
}
}
int lB = 0;
for (int j = 0; j < n; j++) {
if (matrix[i][j] == '1') {
left[j] = Math.max(left[j], lB);
height[j]++;
maxArea = Math.max(maxArea, height[j] * (right[j] - left[j] + 1));
} else {
height[j] = 0;
left[j] = 0;
lB = j + 1;
}
}
}
return maxArea;
}
}