基础算法系列 —— 二维差分

69 阅读2分钟

什么是差分

基础算法系列 —— 一维差分

什么是二维差分

一维差分是针对一个一维数组,快速对这个数组的某一段区间内的所有数都增一个值的结构

二维差分类似,就是在一个二维数组中,快速对某个矩形范围内的数都增加一个值的结构

如果暴力做法,每次都需要遍历将目标矩形中的所有数都加上一个值,时间复杂度较高

如果用二维差分做,每次只用耗时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:

image.png

首先在差分数组b中,给b[x1][y1]加上c:

image.png

根据二维前缀和的定义,这样相当于给所有a中,在(x1,y1)下边和右边的所有点都加上了c,即数组a中的右下部分区域

但其实只用对目标区域加上c,而对于图中的R1,R2,R3这3个区域不需要加上c,需要进行补偿操作:

  • b[x2+1,y1] -= c:相当于给a中R2,R3区域都减去c
  • b[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]);
    }
}