莫比乌斯反演 2021-12-17 22:38 采纳率: 100%
浏览 26
已结题

c语言实现一个前缀和的题

如何用c语言实现一个前缀和呢?
不适合明白前缀的含义

  • 写回答

1条回答 默认 最新

  • 英雄哪里出来 2021年博客之星Top1 2021-12-18 07:15
    关注

    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)$。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论 编辑记录

报告相同问题?

问题事件

  • 系统已结题 12月26日
  • 已采纳回答 12月18日
  • 创建了问题 12月17日

悬赏问题

  • ¥20 wireshark抓不到vlan
  • ¥20 关于#stm32#的问题:需要指导自动酸碱滴定仪的原理图程序代码及仿真
  • ¥20 设计一款异域新娘的视频相亲软件需要哪些技术支持
  • ¥15 stata安慰剂检验作图但是真实值不出现在图上
  • ¥15 c程序不知道为什么得不到结果
  • ¥40 复杂的限制性的商函数处理
  • ¥15 程序不包含适用于入口点的静态Main方法
  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来