前缀和
前言
前缀和是应用于顺序表的算法,用来储存顺序表前n项的和。
一、朴素前缀和
1、部分和
所谓 部分和,就是给定一个数组,求它的某一段连续子数组的和。
2、朴素做法
比较传统的做法,就是对于要求部分和的区间 [l, r],枚举所有的数进行相加,如下:
1 2 3 4 5 6 7 8
| int partialSum(int *a, int l, int r) { int i; int s = 0; for(i = l; i <= r; ++i) { s += a[i]; } return s; }
|
此时时间复杂度最坏为O(mn)。有没有办法优化呢?
3、前缀和
我们可以用一个 sum[] 数组来表示数组的前缀和,即 sum[i] 表示的是前 i 项的和,数学公式如下:
sum[i]=k=0∑ia[k]
将 i-1 代入上述的 i,得到
sum[i−1]=k=0∑i−1a[k]
于是可以得到
sum[i]=sum[i−1]+a[i]
注意由于sum[-1]
非法,因此应当单独定义sum[0] = a[0]
。
4、再看部分和
然后,我们继续来看部分和,有了前缀和数组 sum[] 以后,我们就可以利用差分法,在 O(1) 的时间内求得部分和,原因就是:
k=l∑ra[k]=k=0∑ra[k]−k=0∑l−1a[k]=sum[r]−sum[l−1]
于是,只要预先将前缀和全部求出来,后面每次询问都可以做到 O(1) 了。
二、前缀和变形
1、前缀积
顾名思义,我们可以用一个 prod[] 数组来表示数组的前缀积,即 prod[i] 表示的是前 i 项的积,数学公式如下:
prod[i]=k=0∏ia[k]
将 i-1 代入上述的 i,得到:
prod[i−1]=k=0∏i−1a[k]
于是可以得到
prod[i]=prod[i−1]×a[i]
2、前缀异或和
同样,还有前缀异或和,同样满足这个性质,如下:
xsum[i]=xsum[i−1] xor a[i]
其中xor
为异或运算符^
。(因为不知道在LaTex语法里要怎么打出这个符号所以就这样代替了……)
三、练习
2485. 找出中枢整数 - 力扣(LeetCode)
1588. 所有奇数长度子数组的和 - 力扣(LeetCode)
930. 和相同的二元子数组 - 力扣(LeetCode)
525. 连续数组 - 力扣(LeetCode)