目标值子矩阵的数量问题刷题笔记 | 豆包MarsCode AI 刷题

134 阅读4分钟

问题描述

小M最近在研究矩阵,他对矩阵中的子矩阵很感兴趣,给定一个矩阵matrix和一个目标值 target,他的任务是找到所有总和等于目标值的非空子矩阵的数量 子矩阵通过选择矩阵的某个矩形区域定义,形式为(x1,y1,x2,y2),其中(x1,y1)表示左上角的坐标,(x2,y2)表示右下角的坐标。一个子短阵包含短阵中所 有位于这个矩形区域内的单元格。如果两个子矩阵的坐标不同(如 x1 != x1'或 y1!= y1'),则这两个子矩阵被认为是不同的。 你需要返回满足条件的子矩阵数量。

题目分析

题目内容

  • 给定一个矩阵 matrix 和一个目标值 target,我们需要找到矩阵中所有总和等于目标值的 非空子矩阵 的数量。
  • 子矩阵 是通过选择矩阵的某个矩形区域定义的,可以表示为 (x1, y1, x2, y2),其中 (x1, y1) 是左上角坐标,(x2, y2) 是右下角坐标。
  • 不同的坐标定义的子矩阵被认为是不同的,即使它们的内容相同。

约束

  • 题目没有明确说明矩阵的大小范围,但复杂度取决于矩阵大小,需注意优化算法性能。
  • 矩阵中的元素可以是负数、正数或零。

解题思路

暴力解法

  • 暴力解法通过枚举所有可能的子矩阵坐标 (x1, y1, x2, y2)。
  • 然后计算该子矩阵的元素总和,判断是否等于目标值。
  • 如果相等,则将计数器加一。

问题难点

  • 如何高效计算子矩阵的和?
    • 暴力解法在每次枚举子矩阵时需要重新计算子矩阵内的元素总和,其时间复杂度较高。
  • 如何减少枚举的重复计算?
    • 利用前缀和技巧,快速得到任意子矩阵的和。

复杂度分析

  • 暴力解法需要:
    • 枚举所有的子矩阵,其枚举的复杂度是 𝑂((𝑟𝑜𝑤𝑠⋅𝑐𝑜𝑙𝑠)2)。
    • 每次计算子矩阵的和需要遍历子矩阵内的所有元素,复杂度为𝑂(𝑟𝑜𝑤𝑠⋅𝑐𝑜𝑙𝑠)。
    • 总体时间复杂度是𝑂((𝑟𝑜𝑤𝑠⋅𝑐𝑜𝑙𝑠)3),对于较大矩阵不可接受。
  • 优化解法可以通过减少重复计算,将复杂度降至𝑂(𝑟𝑜𝑤𝑠2⋅𝑐𝑜𝑙𝑠)或更低。

代码思路

暴力解法(当前代码实现)

外层循环:

  • 使用四重嵌套循环,枚举所有可能的子矩阵左上角 (x1, y1) 和右下角 (x2, y2)。 内层计算:
  • 在确定子矩阵的边界后,通过遍历子矩阵的所有单元格,计算子矩阵的总和。
  • 如果总和等于目标值 target,则将计数器 count 加一。 返回结果:
  • 返回统计的子矩阵数量。

代码分析

代码实现

def solution(matrix: list, target: int) -> int:
    rows = len(matrix)  # 获取矩阵的行数
    cols = len(matrix[0])  # 获取矩阵的列数
    count = 0  # 用于计数满足条件的子矩阵数量
    
    # 枚举子矩阵左上角坐标
    for x1 in range(rows):
        for y1 in range(cols):
            # 枚举子矩阵右下角坐标
            for x2 in range(x1, rows):
                for y2 in range(y1, cols):
                    submatrix_sum = 0  # 初始化子矩阵的和
                    # 遍历子矩阵内的所有元素
                    for i in range(x1, x2 + 1):
                        for j in range(y1, y2 + 1):
                            submatrix_sum += matrix[i][j]  # 累加子矩阵元素
                    # 判断子矩阵和是否等于目标值
                    if submatrix_sum == target:
                        count += 1  # 满足条件时计数加一
                        
    return count
  • rows 和 cols 用于获取矩阵的维度。
  • 第一层与第二层循环枚举子矩阵的左上角 (x1, y1)。
  • 第三层与第四层循环枚举子矩阵的右下角 (x2, y2)。
  • 内部通过两层循环,计算当前子矩阵的元素总和。
  • 如果当前子矩阵总和等于目标值,则将计数器增加。

总结

优点

  • 代码逻辑清晰,易于理解。
  • 暴力枚举所有可能的子矩阵,能够保证找到所有满足条件的解。

缺点

  • 效率低下:在大矩阵情况下性能较差,可能会导致超时问题。
  • 可优化方向:
    • 利用 前缀和 降低计算子矩阵总和的时间复杂度。
    • 枚举时优化子矩阵边界选择,避免重复计算。

改进建议

可以通过引入前缀和技巧优化解法,将复杂度降为𝑂(𝑟𝑜𝑤𝑠2⋅𝑐𝑜𝑙𝑠):

  • 固定行边界:通过累加行的方式将二维问题转化为一维问题。
  • 快速求子数组和:在一维问题中使用哈希表快速找到满足条件的子数组数量。 优化版本可以进一步提升性能,适用于更大规模的矩阵输入。