前缀和与差分互为逆运算
目录
一维前缀和
一个长度为n的一维数组
a1 , a2 , a3 …… an
其前缀和数组如下
a1 , (a1+a2) , (a1+a2+a3) …… (a1+a2+a3+……+an)
练习题目:前缀和
java题解
import java.util.Scanner;
public class Main {
public static void main(String args[]) {
Scanner input = new Scanner(System.in);
int n = input.nextInt();
int k = input.nextInt();
int[] nums = new int[n + 10];
int[] result = new int[n + 10];
for (int i = 1; i <= n; i++) {//从第一个下标位置开始接收数据
nums[i] = input.nextInt();
}
for (int i = 1; i <= n; i++) {//求前缀和,上面从第一个下标位置开始接收数据方便求前缀和
result[i] = result[i - 1] + nums[i];//一步一步的刷新数组,这一步的前缀和等于上一步的前缀和加上这一步的数字
}
for (int i = 0; i < k; i++) {//输出查询结果
int left = input.nextInt();
int right = input.nextInt();
System.out.println(result[right] - result[left - 1]);
}
}
}
二维前缀和
i行j列的二维数组,其前缀和表示意义如下
而要求某一部分的面积,可如下表示
练习题目:子矩阵的和
java题解
import java.util.Scanner;
public class Main {
public static void main(String args[]) {
Scanner input = new Scanner(System.in);
int n = input.nextInt();//n行
int m = input.nextInt();//m列
int q = input.nextInt();//q次询问
int[][] nums = new int[n + 10][m + 10];
int[][] result = new int[n + 10][m + 10];//记录二维前缀和的数组
for (int i = 1; i <= n; i++) {//接收数据
for (int j = 1; j <= m; j++) {
nums[i][j] = input.nextInt();
}
}
for (int i = 1; i <= n; i++) {//求前缀和
for (int j = 1; j <= m; j++) {
result[i][j] = nums[i][j] + result[i - 1][j] + result[i][j - 1] - result[i - 1][j - 1];// 求二维前缀和
}
}
for (int i = 0; i < q; i++) {//计算矩阵面积
int x1 = input.nextInt();
int y1 = input.nextInt();
int x2 = input.nextInt();
int y2 = input.nextInt();
System.out.println(result[x2][y2] - result[x1 - 1][y2] - result[x2][y1 - 1] + result[x1 - 1][y1 - 1]);// 输出某一部分的二维前缀和
}
}
}
一维差分
一个长度为n的一维数组
a1 , (a1+a2) , (a1+a2+a3) …… (a1+a2+a3+……+an)
其差分数组如下
a1 , a2 , a3 …… an
练习题目:差分
java题解
import java.util.Scanner;
public class Main {
static int[] result = new int[100010];
public static void Insert(int left, int right, int number) {
result[left] += number;
result[right + 1] -= number;
}
public static void main(String args[]) {
Scanner input = new Scanner(System.in);
int n = input.nextInt();//n个整数
int m = input.nextInt();//m次操作
int[] nums = new int[n + 10];
for (int i = 1; i <= n; i++) {//接收数据
nums[i] = input.nextInt();
}
for (int i = 1; i <= n; i++)// 求差分数组
Insert(i, i, nums[i]);
for (int i = 0; i < m; i++) {//l到r之间的每个数加上c,相当于差分数组在l处加c,在r+1处减c取前缀和
int l = input.nextInt();//这里r+1处必须要减c,不然就是l之后全部加c
int r = input.nextInt();
int c = input.nextInt();
Insert(l, r, c);
}
int[] prefix = new int[100010];
for (int i = 1; i <= n; i++) {//求前缀和
prefix[i] = prefix[i - 1] + result[i];
}
for (int i = 1; i <= n; i++) {//输出
System.out.print(prefix[i] + " ");
}
}
}
二维差分
和求二维前缀和数组有相同之处
练习题目:差分矩阵
java题解
import java.util.Scanner;
public class Main {
static int[][] result = new int[1010][1010];
// 构造差分数组和更新差分数组是同一个道理
public static void Insert(int x1, int y1, int x2, int y2, int number) {
result[x1][y1] += number;
result[x1][y2 + 1] -= number;
result[x2 + 1][y1] -= number;
result[x2 + 1][y2 + 1] += number;
}
public static void main(String args[]) {
Scanner input = new Scanner(System.in);
int n = input.nextInt();//n行
int m = input.nextInt();//m列
int q = input.nextInt();//q次操作
int[][] nums = new int[n + 10][m + 10];
for (int i = 1; i <= n; i++) {//接收数据
for (int j = 1; j <= m; j++)
nums[i][j] = input.nextInt();
}
for (int i = 1; i <= n; i++) {//求二维差分数组
for (int j = 1; j <= m; j++) {
Insert(i, j, i, j, nums[i][j]);
}
}
for (int i = 0; i < q; i++) {//处理操作
int x1 = input.nextInt();
int y1 = input.nextInt();
int x2 = input.nextInt();
int y2 = input.nextInt();
int num = input.nextInt();
Insert(x1, y1, x2, y2, num);
}
for (int i = 1; i <= n; i++) {//再求二维前缀和数组
for (int j = 1; j <= m; j++)
result[i][j] = result[i][j] + result[i - 1][j] + result[i][j - 1] - result[i - 1][j - 1];
}
for (int i = 1; i <= n; i++) {//输出
for (int j = 1; j <= m; j++)
System.out.print(result[i][j] + " ");
System.out.println();
}
}
}