题目要求:
前缀和:对于一维数组数组a,前缀和sum[i]表示从开始到a[i]的所有数字的和(包括a[i])。请把此类问题的特点及常规解决方法进行总结讲解。
1.定义:
一种预处理算法,给定原始数组A,A={A[1],1[2],......A[N]} ,建立差分数组D,使得D[0]=A[0],D[i]=A[i]-A[i-1](1<=i<=N),可以做到在O(1)时间内完成对区间的修改。
数组D成为数组A的差分和,数组A成为数组D的前缀和。
对于已知有n个元素的离线数列d,我们可以建立记录它每项与前一项差值的差分数组f:显然,f[1]=d[1]-0=d[1];对于整数i∈[2,n],我们让f[i]=d[i]-d[i-1]。
对数组b 求前缀和,可以发现就能得到数组a ,所以它保留了数组a的全部信息。而将数组用其差分数组表示的一个优点就是能在O ( 1 ) 时间里将数组中连续的一段加上一个数c 。
2.简单性质:
(1)计算数列各项的值:数列第i项的值是可以用差分数组的前i项和计算的。
(2)计算数列每一项的前缀和:
将[l,r]区间中的数组元素a[i]均加上常数C,如果使用原始算法,则要扫描一下数组a,时间复杂度为O(n);如果使用差分算法则时间复杂度仅为O(1)。具体步骤如下:
a.b[l] + C:当b[l] + C时,a[l]、a[l+1]、......、a[n]均会加C,原因是a[i] = b[1] + b[2] + ... + b[i]
b.b[r + 1] - C:由于需求是将数组a中[l,r]区间中的元素均加C,因此需要将b数组中a[r+1, n]区间中的元素都减去C。这样做才能够抵消b[l] + C步骤中将数组a中[r + 1, n]区间中的元素多加的C给抵消掉,实现真正将[l,r]区间中的数组元素a[i]均加上常数C。
3.用途:
(1)快速处理区间加减操作
假如现在对数列中区间[L,R]上的数加上x,我们通过性质(1)知道,第一个受影响的差分数组中的元素为f[L],即令f[L]+=x,那么后面数列元素在计算过程中都会加上x;最后一个受影响的差分数组中的元素为f[R],所以令f[R+1]-=x,即可保证不会影响到R以后数列元素的计算。这样我们不必对区间内每一个数进行处理,只需处理两个差分后的数即可;
(2)询问区间和问题
由性质(2)我们可以计算出数列各项的前缀和数组sum各项的值;那么显然,区间[L , R]的和即为 ans=sum[R]-sum[L-1]。
4.适用场景:
差分数组的主要适用场景是频繁对原始数组的某个区间的元素进行增减
(1):注意差分数组和前缀和的区别
(2):差分数组适合用于对某个区间频繁的修改值
(3):前缀和适用于对某个区间频繁的求累加和
比如说,输入一个数组nums,然后要求给区间nums[2..8]全部加 10,再给nums[4..12]全部减 3,再给nums[0..6]全部加 4,再给…然后问你,最后nums数组的值是什么?
常规的思路很容易,你让我给区间nums[i..j]加上val,那我就一个 for 循环给它们都加上,这种思路的时间复杂度是 O(N),在这个场景下对nums的修改非常频繁,所以效率会很低下。
这里就需要差分数组的技巧,类似前缀和技巧构造的prefix数组,我们先对nums数组构造一个 diff 差分数组,diff[i] 就是 nums[i] 和 nums[i-1] 之差。