396.小J的字母矩阵问题
题目内容
问题描述
小R拿到了一个 nn 行 mm 列的小写字母矩阵,她想知道有多少个子矩阵满足以下条件:每个字母在这个子矩阵中最多出现一次。
测试样例
样例1:
输入:
n = 2 ,m = 3 ,s = ["aad", "abc"]
输出:13
样例2:
输入:
n = 3 ,m = 3 ,s = ["abc", "def", "ghi"]
输出:36
样例3:
输入:
n = 4 ,m = 4 ,s = ["abcd", "efgh", "ijkl", "mnop"]
输出:100
问题分析
这道题目要求我们在一个字母矩阵中找出所有满足条件的子矩阵,条件是子矩阵中的每个字母最多只能出现一次。这是一个典型的枚举问题,需要我们通过以下步骤来解决:
- 枚举所有可能的子矩阵
- 判断每个子矩阵是否满足条件
- 统计满足条件的子矩阵数量
解题思路详解
子矩阵的枚举方法
要枚举所有可能的子矩阵,我们需要确定子矩阵的左上角和右下角坐标。这需要四重循环:
- 第一重循环:枚举左上角的行坐标(x1)
- 第二重循环:枚举左上角的列坐标(y1)
- 第三重循环:枚举右下角的行坐标(x2),范围从x1到n-1
- 第四重循环:枚举右下角的列坐标(y2),范围从y1到m-1
for x1 in range(n):
for y1 in range(m):
for x2 in range(x1, n):
for y2 in range(y1, m):
# 处理每个子矩阵
子矩阵有效性判断
对于每个子矩阵,我们需要判断是否满足"每个字母最多出现一次"的条件。这个判断可以通过以下步骤实现:
- 创建一个集合(set)用于存储已经出现过的字母
- 遍历子矩阵中的每个字母
- 检查当前字母是否已经在集合中
- 如果在集合中,则返回False(表示不满足条件)
- 如果不在集合中,将其添加到集合中
- 如果遍历完所有字母都没有重复,返回True
def is_valid(x1, y1, x2, y2):
seen = set()
for i in range(x1, x2 + 1):
for j in range(y1, y2 + 1):
if s[i][j] in seen:
return False
seen.add(s[i][j])
return True
结果统计
使用一个计数器(count)来统计满足条件的子矩阵数量:
- 初始化计数器为0
- 每当找到一个满足条件的子矩阵,计数器加1
- 最后返回计数器的值
算法复杂度分析
-
时间复杂度:
- 枚举子矩阵的四重循环:O(n²m²)
- 对每个子矩阵的检查:O(nm)
- 总时间复杂度:O(n³m³)
-
空间复杂度:
- 使用了一个集合来存储字母:O(nm)
- 其他变量为常数空间
- 总空间复杂度:O(nm)
优化可能性
-
提前终止:
- 如果子矩阵的大小超过了字母表的大小(26),那么一定会有重复字母
- 可以在枚举时加入这个判断条件
-
记忆化:
- 可以使用哈希表记录已经判断过的子矩阵的结果
- 但需要权衡存储空间和计算时间的成本
代码健壮性考虑
-
输入验证:
- 检查n和m的有效性(是否为正整数)
- 检查字符串数组s的长度是否为n
- 检查每个字符串的长度是否为m
-
边界情况处理:
- 处理n=0或m=0的情况
- 处理空字符串的情况
通过以上详细的分析和实现,我们可以看到这个问题虽然计算量较大,但思路是清晰的。关键在于准确地枚举所有可能的子矩阵,并高效地判断每个子矩阵是否满足条件。虽然这个解法的时间复杂度较高,但对于给定的测试用例规模来说是可以接受的。在实际应用中,如果需要处理更大规模的数据,可以考虑进一步的优化策略。
完整代码
def solution(n: int, m: int, s: list) -> int:
def is_valid(x1, y1, x2, y2):
seen = set()
for i in range(x1, x2 + 1):
for j in range(y1, y2 + 1):
if s[i][j] in seen:
return False
seen.add(s[i][j])
return True
count = 0
for x1 in range(n):
for y1 in range(m):
for x2 in range(x1, n):
for y2 in range(y1, m):
if is_valid(x1, y1, x2, y2):
count += 1
return count
if __name__ == '__main__':
print(solution(n = 2, m = 3, s = ["aad", "abc"]) == 13)
print(solution(n = 3, m = 3, s = ["abc", "def", "ghi"]) == 36)
print(solution(n = 4, m = 4, s = ["abcd", "efgh", "ijkl", "mnop"]) == 100)