二维区域和检索 - 可变

Submission

运行时间: 55 ms

内存: 19.8 MB

class NumMatrix:

    def __init__(self, matrix: List[List[int]]):
        self.matrix = matrix
        self.P = [list(accumulate([0]+sub)) for sub in matrix]

    def update(self, row: int, col: int, val: int) -> None:
        self.matrix[row][col] = val
        self.P[row] = list(accumulate([0]+self.matrix[row]))

    def sumRegion(self, row1: int, col1: int, row2: int, col2: int) -> int:
        return sum(self.P[r][col2+1]-self.P[r][col1] for r in range(row1, row2+1))

Explain

该题解使用了前缀和技巧。在构造函数中,通过对每一行计算前缀和,并将结果存储在二维数组 P 中。当需要更新某个元素时,只需要更新对应行的前缀和数组即可。在计算区域和时,可以利用前缀和的性质,对于每一行,用区域右端点的前缀和减去左端点的前缀和,然后将所有行的结果累加起来,即可得到最终的区域和。

时间复杂度: 构造函数: O(mn), update: O(n), sumRegion: O(m)

空间复杂度: O(mn)

class NumMatrix:

    def __init__(self, matrix: List[List[int]]):
        # 存储原始矩阵
        self.matrix = matrix
        # 计算每一行的前缀和,并存储在二维数组 P 中
        self.P = [list(accumulate([0]+sub)) for sub in matrix]

    def update(self, row: int, col: int, val: int) -> None:
        # 更新原始矩阵中的元素值
        self.matrix[row][col] = val
        # 重新计算更新行的前缀和数组
        self.P[row] = list(accumulate([0]+self.matrix[row]))

    def sumRegion(self, row1: int, col1: int, row2: int, col2: int) -> int:
        # 计算区域和
        # 对于每一行,用区域右端点的前缀和减去左端点的前缀和,然后将所有行的结果累加
        return sum(self.P[r][col2+1]-self.P[r][col1] for r in range(row1, row2+1))

Explore

在构造函数中,我们首先检查矩阵是否为空,如果为空,则前缀和数组也应该被初始化为空数组。对于只有一行或一列的情况,前缀和的计算方法仍然适用。即使矩阵仅有一个元素,我们同样计算其前缀和,这会是一个由一个元素加上一个初始的0组成的列表。总之,我们的前缀和数组的计算对于任何形状的矩阵都是通用的。

在执行 update 操作时,我们首先在原始矩阵中更新指定位置的元素值。随后,为了确保前缀和数组的正确性,我们会重新计算整个行的前缀和。这种方法确保了即使同一位置进行多次更新,前缀和数组也总是与当前的矩阵状态保持一致,因此不会累积错误的结果。

在 sumRegion 函数中,理论上应该有一步检查来确保输入的索引(row1, col1, row2, col2)都在矩阵的有效边界内。然而,在题解中并未明确这种检查。在实际应用中,应该添加适当的边界检查,如果输入的索引超出矩阵范围,应返回错误或进行适当的处理,以避免运行时错误。

在本题解的前缀和数组设计中,每行的前缀和是独立计算的,不依赖于其他行的数据。因此,更新某个元素时,只需重新计算该元素所在行的前缀和,而不需要考虑列之间的依赖关系。这简化了更新操作,但仍能准确计算任何区域的和,因为区域和的计算是通过逐行计算并累加得到的。