前缀和也是一个容易忽略的知识点,这一章节更多要掌握思想。为了便于大家理解,我们以一道题作为引子:
Q:给定数组arr = {1,2,3,4,5,6,7} ,给定一个Find(Arr , L ,R)Find方法需要实现在数组Arr上,求L-R下标的数组之和。
Eg:求Find(Arr ,3 ,5)与 Find(Arr ,2,6)的值
这题还是很简单,如果大部人去做,每次计算和就是遍历数组,然后累加。但是这样的做法存在一个很大的问题,如果数组规模上万,求和频率达到N的N次方,其空间复杂度是无法计算的。因此,这里就给出了前缀和的思想
给出一个数组Array = {1,2,3,4,5,6,7}
生产前缀和数组Brray = {1,3,6,10,15,21,28}
(前缀和数组,即第N位的数组等于原数组中的第N位 + 前缀和数组中的N-1位
比如说,Brray下标6的数为28 = 原数组下标为6的数 7 + 前缀和数组第6-1位 即 21 )
同样的,我要查询Find( Array, 2 , 5 ) 的值
就相当于是 Brray(5)- Brray(1)
为什么呢?
Brray(5) ==== 表示为 数组下标从 0 ~ 5 区间的总和
Brray(1) ==== 表示为 数组下标从 0 ~ 1 区间的总和
Brray(5)- Brray(1)就相当于表示为 数组下标从 2 ~ 5 区间的总和
也就是Find(2,5)的含义
因此,每次计算前缀和时,都可以一次减法得到值,不用多次遍历数组。
Java代码实现:
public static class RangeSum {
private int[] preSum; //前缀和数组
public RangeSum(int[] array) {
int N = array.length;
preSum = new int[N];
//前缀和数组的首位==原数组的首位
preSum[0] = array[0];
for (int i = 1; i < N; i++) {
//前一位置的数+当前位置的数
preSum[i] = preSum[i - 1] + array[i];
}
}
public int rangeSum(int L, int R) {
//表示两种情况
//如果L=0的话,直接SUM[R] 表示它的值
//如果L≠0的话,需要SUM[R] - SUM[L-1] 表示它的值
return L == 0 ? preSum[R] : preSum[R] - preSum[L - 1];
}
}