AI刷题396.小J的字母矩阵问题问题解析 | 豆包MarsCode AI刷题

70 阅读4分钟

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


问题分析

这道题目要求我们在一个字母矩阵中找出所有满足条件的子矩阵,条件是子矩阵中的每个字母最多只能出现一次。这是一个典型的枚举问题,需要我们通过以下步骤来解决:

  1. 枚举所有可能的子矩阵
  2. 判断每个子矩阵是否满足条件
  3. 统计满足条件的子矩阵数量

解题思路详解

子矩阵的枚举方法

要枚举所有可能的子矩阵,我们需要确定子矩阵的左上角和右下角坐标。这需要四重循环:

  1. 第一重循环:枚举左上角的行坐标(x1)
  2. 第二重循环:枚举左上角的列坐标(y1)
  3. 第三重循环:枚举右下角的行坐标(x2),范围从x1到n-1
  4. 第四重循环:枚举右下角的列坐标(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):
                # 处理每个子矩阵

子矩阵有效性判断

对于每个子矩阵,我们需要判断是否满足"每个字母最多出现一次"的条件。这个判断可以通过以下步骤实现:

  1. 创建一个集合(set)用于存储已经出现过的字母
  2. 遍历子矩阵中的每个字母
  3. 检查当前字母是否已经在集合中
  4. 如果在集合中,则返回False(表示不满足条件)
  5. 如果不在集合中,将其添加到集合中
  6. 如果遍历完所有字母都没有重复,返回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)来统计满足条件的子矩阵数量:

  1. 初始化计数器为0
  2. 每当找到一个满足条件的子矩阵,计数器加1
  3. 最后返回计数器的值

算法复杂度分析

  1. 时间复杂度:

    • 枚举子矩阵的四重循环:O(n²m²)
    • 对每个子矩阵的检查:O(nm)
    • 总时间复杂度:O(n³m³)
  2. 空间复杂度:

    • 使用了一个集合来存储字母:O(nm)
    • 其他变量为常数空间
    • 总空间复杂度:O(nm)

优化可能性

  1. 提前终止:

    • 如果子矩阵的大小超过了字母表的大小(26),那么一定会有重复字母
    • 可以在枚举时加入这个判断条件
  2. 记忆化:

    • 可以使用哈希表记录已经判断过的子矩阵的结果
    • 但需要权衡存储空间和计算时间的成本

代码健壮性考虑

  1. 输入验证:

    • 检查n和m的有效性(是否为正整数)
    • 检查字符串数组s的长度是否为n
    • 检查每个字符串的长度是否为m
  2. 边界情况处理:

    • 处理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)