https://leetcode.com/problems/maximal-square/
https://leetcode.com/problems/maximal-rectangle/
找到01数组中全为1的面积最大的正方形/长方形,返回最大面积
正方形:
二维DP非常简单
public class Solution {
public int maximalSquare(char[][] matrix) {
if (matrix == null || matrix.length == 0) {
return 0;
}
int res = 0;
int row = matrix.length;
int col = matrix[0].length;
int[][] dp = new int[row][col];
for (int i = 0; i < row; i++) {
dp[i][0] = matrix[i][0] - '0';
res = Math.max(res, dp[i][0]);
}
for (int i = 0; i < col; i++) {
dp[0][i] = matrix[0][i] - '0';
res = Math.max(res, dp[0][i]);
}
for (int i = 1; i < row; i++) {
for (int j = 1; j < col; j++) {
if (matrix[i][j] == '1') {
dp[i][j] = Math.min(dp[i - 1][j - 1], Math.min(dp[i][j - 1], dp[i - 1][j])) + 1;
res = Math.max(dp[i][j], res);
}
}
}
return res * res;
}
}
显然可以优化到一维DP,但这里面需要一个trick:如何处理j为0时,状态转移方程中的dp[j - 1]的问题——把dp数组初始化长度多一位,dp[0]废弃,仅用于保证不数组越界。
public class Solution {
public int maximalSquare(char[][] matrix) {
if (matrix == null || matrix.length == 0) {
return 0;
}
int res = 0;
int row = matrix.length;
int col = matrix[0].length;
int[] dp = new int[col + 1];
int pre = 0;
for (int i = 0; i < row; i++) {
for (int j = 1; j <= col; j++) {
int temp = dp[j];
if (matrix[i][j - 1] == '1') {
dp[j] = Math.min(pre, Math.min(dp[j - 1], dp[j])) + 1;
res = Math.max(dp[j], res);
} else {
dp[j] = 0;
}
pre = temp;
}
}
return res * res;
}
}
两解:
解法一:DP
用三个数组height保存以当前位置[i][j]为低的长度为1的柱状图高度(往上数),left保存满足当前高度的最左边位置,right保存满足当前高度的最右边位置。需要注意:right的初始化;right遍历从右向左
public class Solution {
public int maximalRectangle(char[][] matrix) {
if (matrix == null || matrix.length == 0) {
return 0;
}
int res = 0;
int row = matrix.length;
int col = matrix[0].length;
int[] height = new int[col];
int[] left = new int[col];
int[] right = new int[col];
Arrays.fill(right, col);
for (int i = 0; i < row; i++) {
// 当前行,从左向右数1开头的位置
int curLeft = 0;
// 当前行,从右向左数1开头的位置
int curRight = col;
for (int j = 0; j < col; j++) {
if (matrix[i][j] == '1') {
height[j]++;
} else {
height[j] = 0;
}
}
for (int j = 0; j < col; j++) {
if (matrix[i][j] == '1') {
left[j] = Math.max(left[j], curLeft);
} else {
left[j] = 0;
curLeft = j + 1;
}
}
for (int j = col - 1; j >= 0; j--) {
if (matrix[i][j] == '1') {
right[j] = Math.min(right[j], curRight);
} else {
right[j] = col;
curRight = j;
}
}
for (int j = 0; j < col; j++) {
res = Math.max(res, height[j] * (right[j] - left[j]));
}
}
return res;
}
}
解法二:
把整个二维数组看成row个以每一行为底的柱状图,然后用http://blog.youkuaiyun.com/gqk289/article/details/53996163计算柱状图中最大矩形面积,找最大值。
public class Solution {
public int maximalRectangle(char[][] matrix) {
if (matrix == null || matrix.length == 0) {
return 0;
}
int[] heights = new int[matrix[0].length];
int res = 0;
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[0].length; j++) {
if (matrix[i][j] == '1') {
heights[j]++;
} else {
heights[j] = 0;
}
}
res = Math.max(res, count(heights));
}
return res;
}
private int count(int[] heights) {
Stack<Integer> stack = new Stack();
int res = 0;
for (int i = 0; i <= heights.length; i++) {
int height = i == heights.length ? 0 : heights[i];
while (!stack.isEmpty() && height <= heights[stack.peek()]) {
int h = heights[stack.pop()];
int j = stack.isEmpty() ? -1 : stack.peek();
res = Math.max(res, h * (i - j - 1));
}
stack.push(i);
}
return res;
}
}