如何用c语言实现一个前缀和呢?
不适合明白前缀的含义
1条回答 默认 最新
关注 1、部分和
所谓 部分和,就是给定一个数组,求它的某一段连续子数组的和。
2、朴素做法
比较传统的做法,就是对于要求部分和的区间 $[l, r]$,枚举所有的数进行相加,如下:
int partialSum(int *a, int l, int r) { int i; int s = 0; for(i = l; i <= r; ++i) { s += a[i]; } return s; }
函数的返回值代表了求
a[]
数组的第 $l$ 项 到 第 $r$ 项的和,如果数组长度为 $n$,这样做的最坏时间复杂度为 $O(n)$。那么,试想一下,如果有 $m$ 次询问,每次询问都是$O(n)$,时间复杂度就会变成 $O(nm)$,有没有办法优化呢?3、前缀和
我们可以用一个
sum[]
数组来表示数组的前缀和,即sum[i]
表示的是前 $i$ 项的和,数学公式如下:$$sum[i] = a[0] + a[1] + ... a[i] = \sum_{k=0}^{i} a[k]$$ 将 $i-1$ 代入上述的 $i$,得到:$$sum[i-1] = a[0] + a[1] + ... a[i-1] = \sum_{k=0}^{i-1} a[k]$$ 于是可以得到 $$sum[i] = sum[i-1] + a[i]$$。4、前缀和的边界值
有了递推式,我们还需要有一个边界值,从定义出发,边界值应该是:$$sum[-1] = 0$$ 怎么理解呢?试想一下,$sum[1]$ 表示的是从 第0项 累加到 第1项; $sum[0]$ 表示的是从 第0项 累加到 第0项;$sum[-1]$ 表示的是一项都没有累加,那么这个值固然就是零了。即:$$sum[i] = \begin{cases} 0 & i = -1 \ sum[i-1] + a[i] & i \ge 0\end{cases}$$
5、边界处理
这时候,我们需要注意 C 语言中的 下标是从零开始的,所以,$sum[-1]$会导致数组下标越界,可以将它转换成函数的形式将数组
sum[]
进行一次封装:int prefixSum(int n) { if(n == -1) { return 0; } return sum[n]; }
6、再看部分和
然后,我们继续来看部分和,有了前缀和数组
sum[]
以后,我们就可以利用差分法,在 $O(1)$ 的时间内求得部分和,原因就是:$$\begin{aligned} \sum_{k=l}^{r}a[k] &= a[l] + a[l+1] + ... a[r-1] + a[r] \ &= (a[0]+...+a[r]) - (a[0]+...+a[l-1] \ &= \sum_{k=0}^{r}a[k] - \sum_{k=0}^{l-1}a[k] \ &= sum[r] - sum[l-1] \end{aligned}$$
于是,只要预先将前缀和全部求出来,后面每次询问都可以做到 $O(1)$。本回答被题主选为最佳回答 , 对您是否有帮助呢?解决 1无用
悬赏问题
- ¥20 wireshark抓不到vlan
- ¥20 关于#stm32#的问题:需要指导自动酸碱滴定仪的原理图程序代码及仿真
- ¥20 设计一款异域新娘的视频相亲软件需要哪些技术支持
- ¥15 stata安慰剂检验作图但是真实值不出现在图上
- ¥15 c程序不知道为什么得不到结果
- ¥40 复杂的限制性的商函数处理
- ¥15 程序不包含适用于入口点的静态Main方法
- ¥15 素材场景中光线烘焙后灯光失效
- ¥15 请教一下各位,为什么我这个没有实现模拟点击
- ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来