📅  最后修改于: 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)$,因此可以大幅提高计算速度。实现起来也非常简单,只需要按照上述的公式建立差分数组即可。