📜  二维差分数组(1)

📅  最后修改于: 2023-12-03 15:21:40.494000             🧑  作者: Mango

二维差分数组

二维差分数组是一个用于解决二维前缀和问题的优秀算法。它利用了差分的思想,可以在 $O(1)$ 的时间内完成区间修改和查询。

原理

假设有一个矩阵 $matrix$,我们可以建立一个差分数组 $diff$ 来存储原矩阵中相邻元素的差值。即:$diff_{i,j}=matrix_{i,j}-matrix_{i-1,j}-matrix_{i,j-1}+matrix_{i-1,j-1}$。

为什么这里采用相邻元素的差值而不是直接存储本身的值呢?因为对于前缀和问题,我们需要求出一个区域 $[i_1,j_1]$ 到 $[i_2,j_2]$ 的和,如果直接存储的是原矩阵中的值,那么每次查询都需要遍历整个区域,时间复杂度是 $O(n^2)$,无法接受。而如果用差分数组代替,我们只需要求出四个角的值,通过加减运算即可得出答案,时间复杂度变为 $O(1)$。

具体来说,假设需要查询的区域是 $[i_1,j_1]$ 到 $[i_2,j_2]$,那么我们可以得出如下公式:$sum_{i_1,j_1}^{i_2,j_2}=diff_{i_2,j_2}-diff_{i_1-1,j_2}-diff_{i_2,j_1-1}+diff_{i_1-1,j_1-1}$。

当然,如果需要对矩阵进行修改,可以通过更新差分数组来实现。假设要修改矩阵中第 $i,j$ 个元素的值为 $val$,那么我们需要修改 $diff_{i,j}$、$diff_{i+1,j}$、$diff_{i,j+1}$ 和 $diff_{i+1,j+1}$ 四个元素的值。具体公式如下:$diff_{i,j}=val-matrix_{i,j}+matrix_{i-1,j}+matrix_{i,j-1}-matrix_{i-1,j-1}$。

代码实现

二维差分数组的实现非常简单,只需要在初始化时建立差分数组,然后在进行查询和修改时按照上面的公式即可。

class DifferenceArray2D:
    def __init__(self, matrix):
        self.n, self.m = len(matrix), len(matrix[0])
        self.diff = [[0] * (self.m + 1) for _ in range(self.n + 1)]
        for i in range(1, self.n + 1):
            for j in range(1, self.m + 1):
                self.diff[i][j] = matrix[i-1][j-1] - matrix[i-1][j-2] \
                - matrix[i-2][j-1] + matrix[i-2][j-2]
    
    def query(self, i1, j1, i2, j2):
        return self.diff[i2][j2] - self.diff[i1-1][j2] \
        - self.diff[i2][j1-1] + self.diff[i1-1][j1-1]
    
    def update(self, i, j, val):
        diff = val - self.matrix[i-1][j-1] + self.matrix[i-2][j-1] \
        + self.matrix[i-1][j-2] - self.matrix[i-2][j-2]
        self.diff[i][j], i, j = diff, i, j
        while i <= self.n:
            while j <= self.m:
                self.diff[i][j] += diff
                j += j & -j
            i += i & -i
            j = j_start
总结

二维差分数组是一种非常实用的数据结构,可以用于解决二维前缀和问题。由于其时间复杂度为 $O(1)$,因此可以大幅提高计算速度。实现起来也非常简单,只需要按照上述的公式建立差分数组即可。