文章目录
引入
这道题221.最大正方形是这样的:
在一个由 0 和 1 组成的二维矩阵内,找到只包含 1 的最大正方形,并返回其面积。
示例:
输入:
1 0 1 0 0
1 0 1 1 1
1 1 1 1 1
1 0 0 1 0
输出: 4
很明显是用动态规划来解,但是动态规划的方程不容易找到。
221.最大正方形 题解
理解 min(上, 左, 左上) + 1
如题,该题涉及到下列形式的代码:
if (grid(i, j) == 1) {
dp(i, j) = min(dp(i-1, j), dp(i, j-1), dp(i-1, j-1)) + 1;
}
翻译成中文:
若某格子值为 1 ,则以此为右下角的正方形的、最大边长为:上面的正方形、左面的正方形或左上的正方形中,最小的那个,再加上此格。
先来阐述简单共识:
- 若形成正方形(非单 1),以当前为右下角的视角看,则需要:当前格、上、左、左上都是 1
- 可以换个角度:当前格、上、左、左上都不能受 0 的限制,才能成为正方形
直接上图更容易理解:
也就是取3个(左上、左边、上边)正方形的边长的交集,就像木桶短板理论一样。
所以本题代码如下:
public int maximalSquare(char[][] matrix) {
// base condition
if (matrix == null || matrix.length < 1 || matrix[0].length < 1) return 0;
int height = matrix.length;
int width = matrix[0].length;
int maxSide = 0;
// 相当于已经预处理新增第一行、第一列均为0
int[][] dp = new int[height + 1][width + 1];
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
if (matrix[row][col] == '1') {
dp[row + 1][col + 1] = Math.min(Math.min(dp[row + 1][col], dp[row][col + 1]), dp[row][col]) + 1;
maxSide = Math.max(maxSide, dp[row + 1][col + 1]);
}
}
}
return maxSide * maxSide;
}
同理可知,题目:1277. 统计全为 1 的正方形子矩阵,仍然使用相同的思路。
代码如下:
class Solution {
public int countSquares(int[][] matrix) {
if (matrix==null||matrix.length==0||matrix[0].length==0) return 0;
int row=matrix.length;
int col=matrix[0].length;
int count=0;
int[][] dp=new int[row+1][col+1];
for(int i=0;i<row;i++){
for(int j=0;j<col;j++){
if(matrix[i][j]==1){
dp[i+1][j+1]=Math.min(Math.min(dp[i+1][j],dp[i][j+1]),dp[i][j])+1;
count+=dp[i+1][j+1];
}
}
}
return count;
}
}
这里使用count+=dp[i+1][j+1];
,可以思考下为什么这样算是正确的?
比如输入:matrix =
[
[0,1,1,1],
[1,1,1,1],
[0,1,1,1
]
]
我们新加入右下角的1,那么新增了多少个正方形呢?3个,刚好是dp的边长。