目标值子矩阵题目解析 | 豆包MarsCode AI刷题

47 阅读5分钟

题目描述

小M最近在研究矩阵,他对矩阵中的子矩阵很感兴趣。给定一个矩阵 matrix 和一个目标值 target,他的任务是找到所有总和等于目标值的非空子矩阵的数量。

子矩阵通过选择矩阵的某个矩形区域定义,形式为 (x1, y1, x2, y2),其中 (x1, y1) 表示左上角的坐标,(x2, y2) 表示右下角的坐标。一个子矩阵包含矩阵中所有位于这个矩形区域内的单元格。如果两个子矩阵的坐标不同(如 x1 != x1' 或 y1 != y1'),则这两个子矩阵被认为是不同的。

你需要返回满足条件的子矩阵数量。

测试样例

样例1:

输入:matrix = [[-1,1,0], [1,1,1], [0,1,0]] ,target = 0

输出:7

样例2:

输入:matrix = [[-1,-1], [-1,1]] ,target = 0

输出:2

样例3:

输入:matrix = [[-1,2,3], [4,5,6], [7,8,9]] ,target = 10

输出:2

解题思路

前缀和矩阵:我们可以先计算一个前缀和矩阵,其中每个元素 prefix_sum[i][j] 表示从矩阵的左上角 (0, 0) 到 (i, j) 的子矩阵的和。

子矩阵和计算:利用前缀和矩阵,我们可以快速计算任意子矩阵的和。假设我们需要计算从 (x1, y1) 到 (x2, y2) 的子矩阵的和,可以通过以下公式计算: sum = prefix_sum[x2][y2] - prefix_sum[x1-1][y2] - prefix_sum[x2][y1-1] + prefix_sum[x1-1][y1-1]

遍历所有子矩阵:我们需要遍历所有可能的子矩阵,并计算它们的和,检查是否等于目标值。

代码实现

def solution(matrix: list, target: int) -> int:
    # write code here
    rows = len(matrix)
    cols = len(matrix[0]) if rows > 0 else 0

    # 计算前缀和矩阵
    prefix_sum = [[0] * (cols + 1) for _ in range(rows + 1)]
    for i in range(1, rows + 1):
        for j in range(1, cols + 1):
            prefix_sum[i][j] = matrix[i-1][j-1] + prefix_sum[i-1][j] + prefix_sum[i][j-1] - prefix_sum[i-1][j-1]

    count = 0

    # 遍历所有可能的子矩阵
    for x1 in range(1, rows + 1):
        for y1 in range(1, cols + 1):
            for x2 in range(x1, rows + 1):
                for y2 in range(y1, cols + 1):
                    # 计算子矩阵的和
                    submatrix_sum = prefix_sum[x2][y2] - prefix_sum[x1-1][y2] - prefix_sum[x2][y1-1] + prefix_sum[x1-1][y1-1]
                    # 检查是否等于目标值
                    if submatrix_sum == target:
                        count += 1

    return count

    return 0

if __name__ == '__main__':
    print(solution(matrix=[[-1, 1, 0], [1, 1, 1], [0, 1, 0]], target=0) == 7)
    print(solution(matrix=[[-1, -1], [-1, 1]], target=0) == 2)
    print(solution(matrix=[[-1, 2, 3], [4, 5, 6], [7, 8, 9]], target=10) == 2)

关键步骤

计算前缀和矩阵:这部分代码用于计算从 (0, 0) 到 (i, j) 的子矩阵的和。

遍历所有子矩阵:这部分代码用于遍历所有可能的子矩阵,并计算它们的和,检查是否等于目标值。

可能出现的问题 : 如何优化子矩阵求和的时间复杂度?

优化子矩阵求和的时间复杂度可以通过减少不必要的计算来实现。当前的代码使用了四重循环来遍历所有可能的子矩阵,这导致了时间复杂度为 O(n^4),其中 n 是矩阵的边长。我们可以通过使用哈希表来优化这个过程,将时间复杂度降低到 O(n^3)。

优化思路

前缀和矩阵:我们仍然需要计算前缀和矩阵,以便快速计算任意子矩阵的和。

哈希表优化:我们可以使用哈希表来记录每一行的前缀和,并在遍历过程中检查是否存在满足条件的子矩阵。

优化后的代码框架

def solution(matrix: list, target: int) -> int:
    rows = len(matrix)
    cols = len(matrix[0]) if rows > 0 else 0

    # 计算前缀和矩阵
    prefix_sum = [[0] * (cols + 1) for _ in range(rows + 1)]
    for i in range(1, rows + 1):
        for j in range(1, cols + 1):
            prefix_sum[i][j] = matrix[i-1][j-1] + prefix_sum[i-1][j] + prefix_sum[i][j-1] - prefix_sum[i-1][j-1]

    count = 0

    # 遍历所有可能的子矩阵
    for x1 in range(1, rows + 1):
        for x2 in range(x1, rows + 1):
            # 使用哈希表记录每一行的前缀和
            prefix_sum_map = {0: 1}  # 初始化哈希表,包含一个和为0的子矩阵
            for y in range(1, cols + 1):
                # 计算当前行的前缀和
                current_sum = prefix_sum[x2][y] - prefix_sum[x1-1][y]
                # 检查是否存在满足条件的子矩阵
                if current_sum - target in prefix_sum_map:
                    count += prefix_sum_map[current_sum - target]
                # 更新哈希表
                if current_sum in prefix_sum_map:
                    prefix_sum_map[current_sum] += 1
                else:
                    prefix_sum_map[current_sum] = 1

    return count

if __name__ == '__main__':
    print(solution(matrix=[[-1, 1, 0], [1, 1, 1], [0, 1, 0]], target=0) == 7)
    print(solution(matrix=[[-1, -1], [-1, 1]], target=0) == 2)
    print(solution(matrix=[[-1, 2, 3], [4, 5, 6], [7, 8, 9]], target=10) == 2)

关键步骤

计算前缀和矩阵:这部分代码用于计算从 (0, 0) 到 (i, j) 的子矩阵的和。

哈希表优化:在遍历过程中,我们使用哈希表记录每一行的前缀和,并在每次计算当前行的前缀和时,检查是否存在满足条件的子矩阵。

时间复杂度 通过使用哈希表,我们将时间复杂度从 O(n^4) 降低到 O(n^3),其中 n 是矩阵的边长。

总结

本题考查了前缀和矩阵,并给出了优化思路。