什么是差分
什么是二维差分
一维差分是针对一个一维数组,快速对这个数组的某一段区间内的所有数都增一个值的结构
二维差分类似,就是在一个二维数组中,快速对某个矩形范围内的数都增加一个值的结构
如果暴力做法,每次都需要遍历将目标矩形中的所有数都加上一个值,时间复杂度较高
如果用二维差分做,每次只用耗时O(1)
定义:
- 原始数组a
- 差分数组b
a中的每个元素为b中的二维前缀和,即a[i][j] 的值为 在b中,以b[0][0]为左上角,以b[i][j]为右下角的矩形中所有元素的和
例如:要对元素数组a中以4个角为 (x1,y1) (x1,y2) (x2,y1) (x2,y2)
的矩形内的所有元素都加上c:
首先在差分数组b中,给b[x1][y1]加上c:
根据二维前缀和的定义,这样相当于给所有a中,在(x1,y1)下边和右边的所有点都加上了c,即数组a中的右下部分区域
但其实只用对目标区域加上c,而对于图中的R1,R2,R3这3个区域不需要加上c,需要进行补偿操作:
b[x2+1,y1] -= c
:相当于给a中R2,R3区域都减去cb[x1,y2+1] -= c
:相当于给a中R1,R3区域都减去c
可以发现R3区域多减了个c,因此还需要进行补偿:
b[x2+1,y2+1] += c
:相当于给a中R3区域都加上c
这样,每次对原始数组a中某个矩形区域加上c,只用操作差分数组b中的4个位置即可,时间复杂度大大降低
private static void insert(int[][] arr,int x1,int y1,int x2,int y2,int c){
arr[x1][y1] += c;
arr[x2+1][y1] -= c;
arr[x1][y2+1] -= c;
arr[x2+1][y2+1] += c;
}
如何初始化二维差分数组
和一维差分数组的初始化类似,当我们拿到原始数组a后,遍历数组a中的每个元素a[i][j]
按照对以只有该元素的矩形(即左上角a[i][j],右下角a[i][j]的矩形)增加a[i][j]操作即可:
// 差分数组
int[][] diff = new int[n+1][m+1];
for (int i = 0;i<n;i++){
for (int j = 0;j<m;j++){
insert(diff,i,j,i,j,arr[i][j]);
}
}