思想:
就是前缀和的逆运算。
一个数组 a ,需要假象一个数组 b , a[ i ] = b[ 1 ] + b[ 2 ] + b[ 3 ] + ... + b[ i ];
例子:
方法1:加入需要在数组 a 的 [ l ~ r ] 范围内加 c ,按照以往的思维,遍历输入,然后在 l 到 r 的范围内一次加 c 。时间复杂度是O(n)
方法2:运用差分的思想就是,在 b[ l ] 加上 c , b[ r + 1 ] 减去 c 。由于数组 a 是数组 b 的前缀和。思考一下就是得到了 方法1所得到的数组 a。时间复杂度是O(1)
代码的思想与上一篇文章《前缀和的思想是一致的》
一维数组代码如下:
package cn.liyi.day05;
import java.util.Scanner;
public class Demo797 {
public static int N = 10010;
public static int[] a = new int[N];
public static int[] b = new int[N];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入数组的大小和需要操作的次数:");
int n = sc.nextInt();
int m = sc.nextInt();
System.out.println("请输入数组的元素:");
for (int i = 1; i <= n; i++) {
a[i] = sc.nextInt();
insert(i, i, a[i]);
}
while (m-- > 0) {
System.out.println("输入改变位置的边界与值:");
int l = sc.nextInt();
int r = sc.nextInt();
int c = sc.nextInt();
insert(l, r, c);
}
for (int i = 1; i <= n; i++) {
a[i] = a[i - 1] + b[i];
System.out.print(a[i]);
}
}
public static void insert(int l, int r, int c) {
b[l] += c;
b[r + 1] -= c;
}
}
二维数组的代码如下:
package cn.liyi.day05;
import java.util.Scanner;
public class Demo798 {
public static int N = 10010;
public static int[][] a = new int[N][N];
public static int[][] b = new int[N][N];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= m; j ++){
a[i][j] = sc.nextInt();
insert(i, j, i, j, a[i][j]);
}
int q = sc.nextInt();
while (q -- > 0) {
int x1 = sc.nextInt();
int y1 = sc.nextInt();
int x2 = sc.nextInt();
int y2 = sc.nextInt();
int c = sc.nextInt();
insert(x1, x2, y1, y2, c);
}
for(int i = 1; i <= n; i ++)
for (int j = 1; j <=m; j ++){
System.out.print(b[i][j] = b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1]);
System.out.print(" ");
}
}
public static void insert(int x1, int x2, int y1, int y2, int c) {
b[x1][y1] += c;
b[x2 + 1][y1] -= c;
b[x1][y2 + 1] -= c;
b[x2 + 1][y2 + 1] += c;
}
}