问题:
难度:easy
说明:
给定一个二维数组,里面数据只有0 1将里面所有的1组成的正方形统计出来。
输入案例:
Example 1:
// 边长1的正方形有10个,边长2的正方形有4个,边长3正方形有1个,所以一共15个,下同
Input: matrix =
[
[0,1,1,1],
[1,1,1,1],
[0,1,1,1]
]
Output: 15
Explanation:
There are 10 squares of side 1.
There are 4 squares of side 2.
There is 1 square of side 3.
Total number of squares = 10 + 4 + 1 = 15.
Example 2:
Input: matrix =
[
[1,0,1],
[1,1,0],
[1,1,0]
]
Output: 7
Explanation:
There are 6 squares of side 1.
There is 1 square of side 2.
Total number of squares = 6 + 1 = 7.
我的代码:
具体想法跟动态规划差不多,但是我是把每行联通块大小统计,然后统计 边长 <= 一行联通块大小 的正方形有多少个,在leetcode跑是5ms和9ms浮动。
class Solution {
public int countSquares(int[][] matrix) {
int count = 0;
int xlen = matrix.length;
int ylen = matrix[0].length;
// 逐个计算联通块
for(int i = xlen;i -- > 0;) {
A:for(int j = ylen;j -- > 0;) {
// 计算本行联通块, 0的不计算
if(matrix[i][j] != 0) {
// 将本行前一个联通块加进来
matrix[i][j] += j + 1 < ylen ? matrix[i][j + 1] : 0;
// 将本行联通块大小k作为边,往下k行的联通块是否符合要求
for (int k = 0; k < matrix[i][j]; k++) {
if (i + k < xlen) {
// 往下k行的联通块是否符合要求
for(int l = 0;l <= k;l ++) {
if (k >= matrix[i + l][j]) continue A;
}
count ++;
} else break;
}
}
}
}
return count;
}
}
可以换一下思路,使用记忆化搜索(其实也是dp),然后动态规划公式会是这样
// 将前面已经验证的统计数加入当前,取最小是因为排除0,有0的块属于未通过验证
dp[i][j] = 1 + Math.min(dp[i - 1][j], Math.min(dp[i][j - 1], dp[i - 1][j - 1]))
然后代码写好dp之后,再进行优化,可以弄成这样:
class Solution {
public int countSquares(int[][] matrix) {
int n = matrix.length;
int m = matrix[0].length;
// 直接使用matrix作为动态规划数组
int count = 0;
for (int i = n; i -- > 0;){
count += matrix[i][0];
}
// 避免重复元素,所以使用 i -- > 1
for (int i = m; i -- > 1;){
count += matrix[0][i];
}
for (int i = 1; i < n; ++i){
for (int j = 1; j < m; ++j){
if (matrix[i][j] != 0){
// 使用min是因为出现0空心的地方就不进行统计
matrix[i][j] += Math.min(matrix[i - 1][j], Math.min(matrix[i][j - 1], matrix[i - 1][j - 1]));
count += matrix[i][j];
}
}
}
return count;
}
}