1277. 统计全为 1 的正方形子矩阵
大约 4 分钟
---
1277. 统计全为 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. 阶段划分
按照矩阵中每个位置 作为正方形的右下角来划分阶段。对于每个位置,我们计算以它为右下角能构成的全 正方形的最大边长。
2. 定义状态
定义 表示以 为右下角的最大全 正方形的边长。
3. 状态转移方程
当 时,以 为右下角的正方形能有多大,取决于它的三个邻居:
- 左边 能提供的最大边长
- 上边 能提供的最大边长
- 左上角 能提供的最大边长
这三者中的最小值决定了短板,再加上当前格子自身的 ,就是当前位置能形成的最大正方形边长:
如果 ,则 。
为什么取最小值?可以想象一下,要形成一个 的全 正方形,它的右上、左下、右下三个「角」区域都必须至少是 的全 正方形。三个方向中任何一个「不够高」,都会限制最终的大小。
4. 初始条件
第一行()和第一列()的位置,最大边长只能是 本身( 或 )。
5. 最终结果
意味着以 为右下角,可以形成边长分别为 的正方形。所以每个 贡献了 个正方形。把所有 加起来就是答案。
结合示例 1 走一遍:
矩阵:
0 1 1 1
1 1 1 1
0 1 1 1计算 数组:
- 第一行:
- :,第一列 →
- :,
- :,
- :,
- :第一列 →
- :
- :
- :
数组:
0 1 1 1
1 1 2 2
0 1 2 3总和 ,与题目一致。
思路 1:代码
class Solution:
def countSquares(self, matrix: List[List[int]]) -> int:
m, n = len(matrix), len(matrix[0])
# dp 数组,dp[i][j] 表示以 (i,j) 为右下角的最大正方形边长
dp = [[0] * n for _ in range(m)]
ans = 0
for i in range(m):
for j in range(n):
if matrix[i][j] == 1:
if i == 0 or j == 0:
# 边界位置,最大边长就是自身
dp[i][j] = 1
else:
# 取三个邻居的最小值 + 1
dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1
# dp[i][j] 的值就是以 (i,j) 为右下角的正方形个数
ans += dp[i][j]
return ans思路 1:复杂度分析
- 时间复杂度:,需要遍历整个矩阵一次,每个位置进行常数时间的计算。
- 空间复杂度:,需要一个与原始矩阵尺寸相同的 数组。可以优化为 (只保留当前行和上一行),但 时完全不需要。