二维差分
二维差分是一种数据处理技术,应用于二维数组或矩阵中,用来快速计算和更新子矩阵元素的和。它是对一维差分概念的自然扩展,旨在简化对二维数据结构中特定区域元素进行加减操作的过程,同时保持较高的计算效率。通过计算原数组中相邻元素的差异,形成差分数组,从而支持对原数组中任意子矩阵元素进行快速的加法或减法操作,特别适用于需要频繁修改子区域元素值且需要频繁查询子区域和的应用场景,如动态规划问题、图像处理等。
二维差分的定义:
给定一个二维数组 A[i][j]
,其对应的二维差分数组 D[i][j]
可以定义为:
D[i][j] = A[i][j] - A[i-1][j] - A[i][j-1] + A[i-1][j-1]
这里的差分数组 D
尺寸与原数组 A
相同,但其元素值表示了原数组中当前位置 (i, j)
与其上方、左侧和左上方相邻元素之间的数值差异。通过这样的定义,差分数组存储了原数组局部区域的“增量”信息。
二维差分的用途:
主要用途在于,当我们需要对原数组 A
中某个子矩阵区域(例如,以 (i, j)
为左上角,(x, y)
为右下角的子矩阵)的所有元素同时加上或减去一个常数 d
时,使用差分数组 D
可以实现 O(1) 时间复杂度的快速更新,而无需遍历整个子矩阵。具体操作如下:
- 对差分数组
D
中的四个角元素进行更新:
D[i][j] += d
D[x][j] -= d
D[i][y] -= d
D[x][y] += d
完成上述操作后,原数组 A
中指定子矩阵区域内所有元素的总和实际上已经增加了 d * (x - i + 1) * (y - j + 1)
,即完成了对子矩阵所有元素的加法操作。要还原这些变化以得到原数组 A
的实际值,通常会结合使用二维前缀和(也称为累加和矩阵),通过双重累积的方式快速计算出任意子矩阵的和。
二维前缀和
二维前缀和(又称二维累加和或二维累计和)是一种预处理技术,用于快速计算二维数组或矩阵中任意子矩阵的元素和。它通过对原矩阵进行逐行、逐列的累加,生成一个新的二维数组,其中每个元素存储了原矩阵中从原点(通常是左上角 (0, 0)
)到当前位置 (i, j)
的所有元素之和。有了二维前缀和矩阵,可以以常数时间复杂度 O(1) 快速求解原矩阵中任意矩形区域的元素和,极大地提高了计算效率。
二维前缀和的计算过程:
假设我们有一个二维数组 A[i][j]
,目标是计算其对应的二维前缀和矩阵 P[i][j]
。计算过程如下:
- 初始化前缀和矩阵
P
的第一个行和第一个列:
P[0][0] = A[0][0]; for (int j = 1; j < N; ++j) P[0][j] = P[0][j - 1] + A[0][j]; // 计算第一行的前缀和 for (int i = 1; i < M; ++i) P[i][0] = P[i - 1][0] + A[i][0]; // 计算第一列的前缀和
- 计算剩余部分的前缀和:
for (int i = 1; i < M; ++i) for (int j = 1; j < N; ++j) P[i][j] = P[i - 1][j] + P[i][j - 1] - P[i - 1][j - 1] + A[i][j];
二维前缀和的应用:
二维前缀和主要应用于需要频繁计算二维数组或矩阵中子矩阵元素和的场景,如动态规划、图像处理、统计分析等。具体应用示例包括
sum = P[i2][j2] - P[i1][j2] - P[i2][j1] + P[i1][j1];
- 这里通过相减操作消除了不需要计算的区域和。
- 快速更新子矩阵:结合二维差分技术,可以在常数时间内对原矩阵中的子矩阵元素进行增减操作,并保持二维前缀和的有效性。
- 解决特定问题:在一些基于子矩阵操作的算法中,如最大子矩阵和、连续子数组的最大和等,二维前缀和可以显著提高算法的效率。
二维差分与二维前缀和的关系:
二维差分和二维前缀和是互补的概念。二维前缀和数组 S[i][j]
存储了原数组从 (1, 1)
到 (i, j)
所有元素的累计和。二者之间存在一定的互逆关系,即可以通过差分数组和前缀和数组相互转换或配合使用来高效地进行数据查询和更新。