📅  最后修改于: 2023-12-03 15:35:51.843000             🧑  作者: Mango
给定一个大小为m x n的布尔矩阵mat。询问mat中的所有“全真子矩阵”有多少个。
这里所谓“全真子矩阵”是指一个矩阵中所有元素均为true。比如说对于下面这个矩阵
1 1 1
1 1 1
1 1 1
它的全真子矩阵有:
1 1
1 1
1 1 1
1 1 1
1 1 1
1 1 1
1 1 1
共三个。
这是一道很有名的计数问题,解法被称为“状压DP”,或者称作“二进制状压”。
具体来说,我们用一个二进制数来表示一个子矩阵。对于一个大小为m x n的矩阵,这个二进制数的第i位表示矩阵中第i个元素是否在该子矩阵中。
例如,对于下面这个矩阵:
0 1 1
1 0 1
1 1 1
其中元素1-9对应的二进制为:
1 0 0 0 1 0 0 1 1
我们可以遍历所有的二进制数,对于每个二进制数,判断其是否为全真子矩阵。
具体来说,对于一个二进制数x,我们可以用以下方式判断其是否为一个全真子矩阵:
具体实现参考代码:
def countSubmat(mat) -> int:
m, n = len(mat), len(mat[0])
ans = 0
for i in range(m):
# 枚举每一行的起始位置
row = 0
for j in range(i, m):
# 更新当前矩阵的列与行
row |= int(''.join(map(str, mat[j])), 2) # 按二进制转化为整数
col = 0
for k in range(n):
col = (col << 1) | (row >> (n - 1 - k) & 1) # 构造完整列矩阵的二进制数
cur = bin(col & (col + 1)).count('1') # 计算全真子矩阵个数
ans += cur
return ans
时间复杂度:O(mnlgn),其中lgn是一个int二进制数的位数,本算法为状态压缩法,枚举所有子矩阵,从而达到了O(mnlgn)的时间复杂度。
空间复杂度:O(mn),需要额外的空间记录每一行的二进制数。
算法基础课:刘汝佳著,黄亮主讲
希望这篇文章对你有所帮助。