Given a 2D binary matrix filled with 0's and 1's, find the largest square 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: 4
这题其实很明显是一道dp题来的。我猜当然也是可以暴力做的,但我没有往那方面想
虽然要求的是正方形的面积,其实求的还是最长的边长。正方形由于要求长和高是一样的,所以一个二维数组就足够记录了。这个二维数组里记录的是当前点所有的最大的边长,这个最大的边长来自于自上往下的延续,自左往右的延续,以及对角线方向的延续。给出递归式如下:
f(i, j) = input(i, j) == 1 ? min(f(i - 1, j), f(i, j - 1), f(i - 1, j - 1)) + 1 : 0
需要注意的是,这个递归式求出的是当前点所对应的最大边长,并非是全局到这一点的最大边长。所以你一边计算的时候还需要一边记录当前遇到过的最大边长。给出代码如下:
public int maximalSquare(char[][] matrix) {
if (matrix.length == 0 || matrix[0].length == 0) return 0;
int[][] dp = new int[matrix.length][matrix[0].length];
int result = 0;
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[0].length; j++) {
if (matrix[i][j] == '0') {
dp[i][j] = 0;
continue;
}
int lefttop = (i <= 0 || j <= 0) ? 0 : dp[i - 1][j - 1];
int left = j <= 0 ? 0 : dp[i][j - 1];
int top = i <= 0 ? 0 : dp[i - 1][j];
dp[i][j] = Math.min(left, Math.min(lefttop, top)) + 1;
result = Math.max(dp[i][j], result);
}
}
return result * result;
}
当然,因为f(i, j)都只是涉及到上一层的操作,按照过往经验,可以简化成空间是一维的
public int maximalSquare(char[][] matrix) {
if (matrix.length == 0 || matrix[0].length == 0) return 0;
int[] curDp = new int[matrix[0].length];
int[] prevDp = new int[matrix[0].length];
int result = 0;
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[0].length; j++) {
if (matrix[i][j] == '0') {
curDp[j] = 0;
continue;
}
int lefttop = (i <= 0 || j <= 0) ? 0 : prevDp[j - 1];
int left = j <= 0 ? 0 : curDp[j - 1];
int top = i <= 0 ? 0 : prevDp[j];
curDp[j] = Math.min(left, Math.min(lefttop, top)) + 1;
result = Math.max(curDp[j], result);
}
System.arraycopy(curDp, 0, prevDp, 0, prevDp.length);
Arrays.fill(curDp, 0);
}
return result * result;
}