动态规划
思路
-
用dp(i,j)=x既可以表示以(i,j)为右下角的正方形的数目(即边长为1,2..,x的正方形各一个),也可以表示以(i,j)为右下角的正方形的最大边长。
-
计算出所有dp(i,j)的值并进行累加,即为所求。
-
dp(i,j)与相邻位置的关系,参考官方讲解
代码
/**
* 7ms 动态规划
* @param matrix
* @return
*/
public int countSquares(int[][] matrix) {
int ans = 0;
if (matrix == null || matrix.length == 0 || matrix[0].length == 0) return 0;
int r = matrix.length, c = matrix[0].length;
int[][] dp = new int[r][c];
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
if (matrix[i][j] == 1) {
//边界处理 i==0或者j==0
if (i == 0 || j == 0) {
dp[i][j] = 1;
ans++;
} else {
//递推公式
dp[i][j] = Math.min(Math.min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]);
ans += dp[i][j];
}
}
}
}
return ans;
}
暴力解法
思路
- 从头开始遍历,以(i,j)为正方形的左上角
- 计算以(i,j)为左上角,且可能构成正方形的最大边长 curMaxSide
- 在不超过curMaxSide条件下 边长逐步加1 判断是否满足题设要求
- 先判断对角线上的点 (i+k,j+k), 因为边长每延长1 就多出的 一列 一行 ,而该点即为多出的一行一列的公共点
- 再判断一行一列各个元素值是否满足题设
- 若符合 累加 ,否则退出循环 退出嵌套for循环需注意细节:可以引用flag标记退出外层循环
代码
/**
* 7ms
* 暴力解法
*/
public int countSquares2(int[][] matrix){
int ans=0;
if(matrix==null||matrix.length==0||matrix[0].length==0) return ans;
int r=matrix.length,c=matrix[0].length;
for(int i=0;i<r;i++){
for(int j=0;j<c;j++){
if(matrix[i][j]==1){
ans++;
//以(i,j)为左上角 能构成最大正方形的长度
int curMaxSide=Math.min(r-i, c-j);
for(int k=1;k<curMaxSide;k++){
boolean flag=true;
//先判断对角线 该点其实是多出的 一行 一列的公共点
if(matrix[i+k][j+k]==0){
break;
}
//边长增加1 判断多出来的一行 一列 的元素值 是否为 1
for(int m=0;m<k;m++){
if(matrix[i+k][j+m]==0||matrix[i+m][j+k]==0){
flag=false;
break;
}
}
if(flag){
ans++;
}else{
break;
}
}
}
}
}
return ans;
}