📅  最后修改于: 2023-12-03 15:36:45.787000             🧑  作者: Mango
在一个二维01矩阵中,全为1的子矩阵是指连续的若干行和若干列组成的矩阵,其中所有的元素都为1。给定一个矩阵,计算其中全为1的子矩阵的数量。
一个直接的想法是,对于矩阵中的每一个元素,以它为左上角,向右和向下扩展,计算以此为左上角的全为1的子矩阵数量。但是这种方法时间复杂度为O(n^6),无法通过大规模数据。
动态规划可以使得时间复杂度降为O(n^3)。定义dp[i][j]表示以第i行第j列为右下角的全为1的子矩阵的数量,那么状态转移方程为:
dp[i][j] = dp[i-1][j] + dp[i][j-1] - dp[i-1][j-1] + 1 (matrix[i][j] == 1) dp[i][j] = 0 (matrix[i][j] == 0)
解释一下:以第i行第j列为右下角的全为1的子矩阵,可以由以下三种情况得到:
但是这样会算重复,所以要把以第(i-1)行第(j-1)列为右下角的全为1的子矩阵的数量减去。
时间复杂度:O(n^3)
单调栈可以使得时间复杂度降为O(n^2)。维护一个height数组,height[j]表示第i行第j列上方连续为1的个数。那么问题就转化为了给定一个直方图,计算其中全为1的子矩阵的数量。
我们枚举每一行i,把这一行作为底,然后将height数组看做一个直方图,利用单调栈可以求出以这一行为底的最大全为1子矩阵的面积。这个面积就是以第i行第j列为右下角的全为1的子矩阵的数量。
时间复杂度:O(n^2)
def countSubmat(matrix):
m, n = len(matrix), len(matrix[0])
dp = [[0] * n for _ in range(m)]
res = 0
for i in range(m):
for j in range(n):
if matrix[i][j] == 1:
dp[i][j] = dp[i-1][j] + dp[i][j-1] - dp[i-1][j-1] + 1
res += dp[i][j]
return res
def countSubmat(matrix):
m, n = len(matrix), len(matrix[0])
height = [0] * n
res = 0
for i in range(m):
for j in range(n):
if matrix[i][j] == 0:
height[j] = 0
else:
height[j] += 1
k = j
while k >= 0 and height[k] > 0:
res += height[k]
k -= 1
return res
全为1的子矩阵数是一个有趣的问题,它有多种解决方法,其中动态规划和单调栈都是比较好的解决方法。这个问题的解决方法也可以应用到其他问题中,如最大全为1的子矩阵面积、最大全为0的子矩阵面积等。