题目描述
首先,暴力解就是以矩阵每一个点为起点,依次判断边长为1,2,3,...,min
(矩阵长, 矩阵宽)的区域是否是正方形,显然复杂度是过不了。
很容易知道,上述过程在判断较大区域是否为正方形的时候,并没有用到前面计算的结果,每一次判断都从头开始。这也是复杂度过高的原因。
那么怎么利用之前判断过的结果呢?举个例子,比如我要判断以(2, 3)为右下角边长为3的正方形区域(红色边框区域)是否是全为1:
先判断(i, j)位置是否为1,如果否,则显然不满足;如果是,进行下一步判断
判断分别以
(i - 1, j), (i - 1, j - 1), (i, j - 1)
为右下角的区域是否能构成边长为2的正方形,如果能,那就满足条件。
基于上述,我们可以看出思路大致跟最大正方形那题差不多,设dp[i][j][k]
表示以(i, j)
为右下角,边长为k
的正方形区域是否全为1
,那么易得出如下状态转移方程:dp[i][j][k] = (matrix[i][j] == 1 && dp[i - 1][j][k - 1] && dp[i][j - 1][k - 1] && dp[i - 1][j - 1] [k - 1]);
int countSquares(vector<vector<int>>& matrix) {
r = matrix.size();
c = matrix[0].size();
int dp[r][c];
memset(dp, 0, sizeof(dp));
int count = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
dp[i][j][0] = (matrix[i][j] == 1);
count += dp[i][j][0] ? 1 : 0;
}
}
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
for (int k = 1; k < len; k++) {
dp[i][j][k] = (matrix[i][j] == 1 && dp[i - 1][j][k - 1] && dp[i][j - 1][k - 1] && dp[i - 1][j - 1] [k - 1]);
if (dp[i][j][k]) {
count++;
}
}
}
}
return count;
}
优化
首先,题目并不关心边长为1,2,…,k的各有多少个,并且我们知道,以(i, j)为右下角边长为k的正方形全为1的话,那么以(i, j)为右下角边长分别为1,2,…,k - 1的正方形区域一定是全为1,如下图:
上图中,如果红色区域是边长为3的全1正方形区域,那么它一定包含了一个边长为2和边长为1的全1正方形区域。所以,我们只需记录以(i, j)
为右下角的区域包含的最大全1正方形边长即可,这个最大边长也即以(i , j)
为右下角的全1正方形的个数.
那么基于此,我们就可以将原始的dp
降一维度,设dp[i][j]
表示以(i, j)
为右下角的最大全1正方形区域的边长,则有如下状态转移方程:
dp[i][j] = Math.min(Math.min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]) + 1;
这就和最大正方形那题的状态转移方程完全一样了。
int countSquares(vector<vector<int>>& matrix) {
r = matrix.size();
c = matrix[0].size();
int ans = 0;
int dp[r][c];
memset(dp, 0, sizeof(dp));
for(int i = 0; i < r; i++)
ans += dp[i][0] = matrix[i][0];
for(int j = 1; j < c; j++)
ans += dp[0][j] = matrix[0][j];
for(int i = 1; i < r; i++)
{
for(int j = 1; j < c; j++)
{
if(matrix[i][j])
{
dp[i][j] = min(min(dp[i-1][j],dp[i][j-1]), dp[i-1][j-1]) + 1;
ans += dp[i][j];
}
}
}
return ans;
}
时间复杂度:O(MN)
空间复杂度:O(MN)
注:本文引用自https://leetcode-cn.com/problems/count-square-submatrices-with-all-ones/solution/tong-ji-quan-wei-1-de-zheng-fang-xing-zi-ju-zhen-f/