算法记录
LeetCode 题目:
给你一个 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.
二、分析
- 当前点是否能够组成一个全
1
的正方形的必要条件是当前点为一,这个毋庸置疑,说了也当白说,混字数。 - 如果当前点想要组成一个更大的正方形,那么他就需要去看当前点的左上角的三个点组成正方形的情况,因为我们遍历的时候是从左至右、从上至下的,当前点就是整个可能组成正方形的左下点。
- 上述的步骤只能供我们得出当前点能组成的最大正方形是多大,但是我们并不知道整体的正方形个数是多少。
- 这里我们还要有一个小结论,就是如果当前点能组成的最大正方形是
3 * 3
,那么一定能组成1 * 1
、2 * 2
,很简单,简单到都不知道怎么表达,可以自己下去推一下。 - 有了上面的结论之后,我们只需要遍历一遍每个点能组成的最大正方形并且相加就可以得到最终能组成正方形的数量,为了减少遍历带来的时间损失,这里在构建正方形时就直接添加最终结果。
class Solution {
public int countSquares(int[][] matrix) {
int m = matrix.length, n = matrix[0].length, max = 0;
int[][] flag = new int[m][n];
for(int i = 0; i < m; i++) {
if(matrix[i][0] == 0) continue;
flag[i][0] = matrix[i][0];
max++;
}
for(int j = 1; j < n; j++) {
if(matrix[0][j] == 0) continue;
flag[0][j] = matrix[0][j];
max++;
}
for(int i = 1; i < m; i++) {
for(int j = 1; j < n; j++) {
if(matrix[i][j] == 0) continue;
flag[i][j] = Math.min(flag[i - 1][j - 1], Math.min(flag[i - 1][j], flag[i][j - 1])) + 1;
max += flag[i][j];
}
}
return max;
}
}
总结
动态规划。