本题出自力扣题库第1277题。题面大意如下:
给定一个m*n 的矩阵,矩阵中的每个元素的值是0或1,返回其中完全由1组成的正方形子矩阵的个数。
示例:
输入:matrix =
[
[0,1,1,1],
[1,1,1,1],
[0,1,1,1]
]
输出:15
解释:
边长为 1 的正方形有 10 个。
边长为 2 的正方形有 4 个。
边长为 3 的正方形有 1 个。
正方形的总数 = 10 + 4 + 1 = 15.
题解:
本题属于矩阵类的DP应用,对于此类问题,需要画图以理解矩阵元素之间的关系。上面给出的示例可以画成如下的图形。
其中我们挑选标为A的这个元素用于分析,首先因为A是1,所以就多了一个边长为1的正方形,下来我们看A是否是边长为2的正方形的右下角呢?这取决于B,C,D三点是否都是1,然后,A是否是边长为3的正方形的右下角呢?这取决于B,C,D三点是否都是边长为2的正方形的右下角。由此类推,我们可得如下的DP表达式:
F(i, j)
= 0, matrix[i][j] = 0
= 1 + min (F(i - 1), F(i - 1, j - 1), F(i, j- 1))
这里i和j是矩阵元素的下标,F(i, j) 返回的是该元素作为右下角的正方形的数量。我们使用双层循环依次对矩阵中的各个元素进行计算,而其总和就是问题的最终答案。
Java代码如下:
class Solution {
public int countSquares(int[][] matrix) {
int n = matrix.length;
int m = matrix[0].length;
int count = 0;
int[][] dp = new int[n + 1][m + 1];
for (int row = 1; row <= n; row++) {
for (int col = 1; col <= m; col++) {
if (matrix[row - 1][col - 1] == 1) {
int min = Math.min(dp[row - 1][col - 1], dp[row - 1][col]);
min = Math.min(min, dp[row][col - 1]);
dp[row][col] = 1 + min;
count += dp[row][col];
}
}
}
return count;
}
}