leetcode 1277
统计全为1的正方形子矩阵
给你一个m*n的矩阵,矩阵中的元素不是0就是1,请你统计并返回其中完全由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.
示例2:
输入:matrix =
[
[1,0,1],
[1,1,0],
[1,1,0]
]
输出:7
解释:
边长为 1 的正方形有 6 个。
边长为 2 的正方形有 1 个。
正方形的总数 = 6 + 1 = 7.
解法1:右下方扩展法
思路:其实一个大的正方形矩阵可以有小的正方形组成,我们对每一个正方形往左下方扩展,就能得到正方形的个数,举个例子
1,1,1,1
1,1,1,0
1,0,1,0
我们看第一个元素,往外扩展一圈,得到元素是1,1,1,再扩展一圈,得到的是1,1,1,0,1,发现有一个不是正方形,我们就退出扩展,返回扩展的长度1,依次类推,就能得到正方形子矩阵的个数
完整代码
int expand(int i, int j, int dp[MAXN][MAXN], int rowsize, int colsize)
{
if(dp[i][j]==0)
return 0;
int size=1; //扩展长度
int row, col;
while(size)
{
if(i+size>=rowsize || j+size>=colsize) //超过范围
return size-1;
for(row=i+size,col=j; col<=j+size; col++) //遍历外围行
if(dp[row][col]==0)
return size-1;
for(col=j+size,row=i; row<=i+size; row++)//遍历外围列
if(dp[row][col]==0)
return size-1;
size++;
}
}
int countSquares(int matrix[MAXN][MAXN], int rowsize, int colsize){
int dp[MAXN][MAXN];
int i, j;
int num=0;
for(i=0; i<rowsize; i++)
for(j=0; j<colsize; j++)
dp[i][j]=matrix[i][j];
for(i=0; i<rowsize; i++)
for(j=0; j<colsize; j++)
dp[i][j]+=expand(i,j,dp,rowsize,colsize);
//用dp存放它所扩展出去的正方形子矩阵个数
for(i=0; i<rowsize; i++)
for(j=0; j<colsize; j++)
num+=dp[i][j];
return num;
}
时间复杂度为O(MNMAX(M,N)),在遍历二维数组的时候时间复杂度为O(M*N),在扩展时还需要遍历一行一列数据
空间复杂度为O(M*N),二维数组(dp)的大小
解法2:动态规划
这一解法是leetcode官方解法,前面的解法是我自己的解法
思路:该解法和上面解法思路基本相同,但是在扩展的时候,使用了动态规划的思想,因此我们需要先了解一下它的动态规划转移方程是怎样的,还有它是如何推导得到的
先看一个例子
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
我们用f(i,j)作为一个正方形的右下角,它保存着正方形子矩阵的个数
我们可以看到,f(i,j-1),f(i-1,j),f(i-1,j-1)都表示3个正方形矩阵个数,也就是f(i,j)-1,即f(i,j-1),f(i-1,j),f(i-1,j-1)至少等于f(i,j)-1,因此我们可以得到转移方程

完整代码
int min(int a, int b, int c)
{
if(a<b&&a<c)
return a;
if(b<a&&b<c)
return b;
if(c<a&&c<b)
return c;
}
int countSquares(int matrix[MAXN][MAXN], int rowsize, int colsize){
int dp[MAXN][MAXN];
int i, j;
int num=0;
for(i=0; i<rowsize; i++)
{
for(j=0; j<colsize; j++)
{
if(i==0 || j==0)
dp[i][j]=matrix[i][j];
else if(matrix[i][j]==0)
dp[i][j]=0;
else
dp[i][j] = min(dp[i][j-1],dp[i-1][j],dp[i-1][j-1])+1;
num += dp[i][j];
}
}
return num;
}
时间复杂度O(M*N)只需遍历一遍二维数组
空间复杂度O(M*N),保存值dp数组
体会
该算法比我的要好得多,不仅简洁,而且时间复杂度降低,其实算法思路是一样的,但是动态规划的思想就是减少重复运算,保存已经计算过的值,以便后来可以重复使用,使用动态规划时应该找出边界条件还有状态转移方程
题目来源以及解法参考:
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/count-square-submatrices-with-all-ones/solution/tong-ji-quan-wei-1-de-zheng-fang-xing-zi-ju-zhen-2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
该博客介绍了如何解决LeetCode 1277题——统计全为1的正方形子矩阵的问题。提供了两种解法,分别是右下方扩展法和动态规划法。解法1通过不断扩展每个元素得到正方形个数,时间复杂度为O(MNMAX(M,N));解法2利用动态规划降低时间复杂度到O(M*N)。博客强调了动态规划的优势在于避免重复运算,提高效率。"
111569466,7167548,matplotlib.pyplot文本插入详解,"['数据可视化', 'Python库', 'matplotlib', '图形绘制']

被折叠的 条评论
为什么被折叠?



