求一个数组(L - R)位置的累加和
假设有一个数组arr,下面表格表示当前数组的数据
数组值 | 3 | 2 | 9 | 5 | 8 | 7 |
数组下标 | 0 | 1 | 2 | 3 | 4 | 5 |
第一种方式:可以生成一个矩阵形式的表(L在下图位置表示纵向位置的坐标,R在下图位置表示横向位置的坐标),这种方式比较浪费空间,但是查询效率会高,因为查L - R 位置的累加和,可以从中直接取出值,不需要再次计算。
数组下标R/数据下标L | 0 | 1 | 2 | 3 | 4 | 5 |
0 | 3 | 5 | 14 | 19 | 27 | 34 |
1 | X | 2 | 11 | 16 | 24 | 31 |
2 | X | X | 9 | 14 | 22 | 29 |
3 | X | X | X | 5 | 13 | 20 |
4 | X | X | X | X | 8 | 15 |
5 | X | X | X | X | X | 7 |
表格中单元格中的值表示数组 L - R 位置上值的累加和,单元格中值为 X 表示无效范围,不会出现 1 - 0,2 - 0,2 - 1,3 - 0,3 - 1, ······ 范围的值;
表格第一行 表示 0 - 0 位置上的累加和为数组arr[0] 值 3, 0 - 1 位置的累计和为5,0 - 2 位置的累计和为14,······ 0 - 5 位置的累计和为34;
第二行 表示 1 - 0 位置 为无效范围,1 - 1 位置的累计和为2,1 - 2 位置的累计和为11,1 - 3 位置的累计和为16,1 - 4 位置的累计和为24,1 - 5 位置的累计和为31;
······
public class RangSum {
/**
* 帮助查询 数组
* 保存 0 - 1,0 -2 ,0 - 3 ,······ ,0 - N 位置的 累加和
* 1 - 1 ,1 - 2, 1 - 3,······ ,0 - N 位置的 累加和
*/
private int[][] rangSum;
/**
*生成 累加和 矩阵
*/
public void generateRangSum(int[] arr) {
int length = arr.length;
rangSum = new int[length][length];
for (int i = 0; i < length; i++) {
for (int j = i; j < length; j++) {
if(j > i){
rangSum[i][j] = rangSum[i][j-1] + arr[j];
}/*else if(i > j){ //因为第二层循环 每次都是从i位置开始,所以不会有 i > j 的情况,所以可以省略当前判断
rangSum[i][j] = 0;
}*/else {
rangSum[i][j] = arr[j];
}
}
}
}
/**
* 获取L - R 范围的累加和
* @param L 开始下标
* @param R 结束下标
* @return
*/
public int getRangSum(int L,int R){
return rangSum[L][R];
}
public static void main(String[] args) {
int[] arr = {3,2,9,5,8,7};
RangSum rangSum = new RangSum();
rangSum.generateRangSum(arr);
System.out.println(rangSum.getRangSum(1,2));
// 结果 11
}
}
第二种方式:可以用一个数组H保存0 - 0 位置,0 - 1 位置,0 - 2 位置,······,0 - N 位置的前缀和。这种方式节省空间,但查询效率不如第一种,需要计算一次。
数组下标R/数据H | 0 | 1 | 2 | 3 | 4 | 5 |
H[] | 3 | 5 | 14 | 19 | 27 | 34 |
假设查询 2 - 4 位置的累加和,(H[4] - H[2-1])只需取出 数组H,4 位置的值27 和 2 - 1 位置的值5,27 - 5,即可得到结果 22。
public class RangSum {
/**
* 帮助查询 数组
* 保存 0 - 1,0 -2 ,0 - 3 ,······ ,0 - N 位置的 前缀和
*/
private int[] preSum;
public void generatePreSum(int[] arr){
preSum = new int[arr.length];
//0 - 0 位置的结果是是数组arr[0]自己本身,提前可以确定
preSum[0] = arr[0];
/**
* 0 - 1 位置的前缀和等于 arr[0] + arr[1]
* 0 - 2 位置的前缀和等于 arr[0] + arr[1] + arr[2] = 0 - 1 位置的前缀和(perSum[1]) 加 arr[2]
* 0 - 3 位置的前缀和等于 arr[0] + arr[1] + arr[2] + arr[3] = 0 - 2 位置的前缀和(perSum[2]) 加 arr[3]
* ······
*/
for (int i = 1; i < arr.length; i++) {
preSum[i] = preSum[i-1] + arr[i];
}
}
/**
* 获取L - R 范围的累加和
* @param L 开始下标
* @param R 结束下标
* @return
*/
public int getRangSum(int L,int R){
if(L > R){
return 0;
}
return L == 0 ? preSum[R] : preSum[R] - preSum[L - 1];
}
public static void main(String[] args) {
int[] arr = {3,2,9,5,8,7};
RangSum rangSum = new RangSum();
rangSum.generatePreSum(arr);
System.out.println(rangSum.getRangSum(1,2));
// 结果 11
}
}