java前缀和(原理+代码)

java前缀和(原理+代码),第1张


Prefix sum( 前缀和 )

用于解决原数组不变,多次求区间和的问题。

输入整数数组 [ n u m s ] [ nums ] [nums] 和查询数组 [ f i n d S u m ] [ findSum ] [findSum],每个查询包含两个整数 l l l r r r ,表示查询第 l l l 个数到第 r r r 个数的和
(注意 : 是第 l l l 个数到第 r r r 个数,也就是 n u m s [ 0 ] nums [ 0 ] nums[0] 为第一个数)

  • 对于 n n n 个数,先创建一个长度为 n + 1 n+1 n+1 的前缀和数组 [ p r e f i x S u m ] [prefixSum] [prefixSum]
  • p r e f i x S u m [ 0 ] = 0 prefixSum[0]=0 prefixSum[0]=0
  • p r e f i x S u m [ i ] = p r e f i x S u m [ i − 1 ] + n u m s [ i − 1 ] prefixSum[i]=prefixSum[i-1]+nums[i-1] prefixSum[i]=prefixSum[i1]+nums[i1]
  • s u m ( l , r ) = p r e f i x S u m [ r ] − p r e f i x S u m [ l − 1 ] sum(l,r)=prefixSum[r]-prefixSum[l-1] sum(l,r)=prefixSum[r]prefixSum[l1]
证明

p r e f i x S u m 简 写 为 p r e prefixSum简写为pre prefixSumpre
p r e [ l − 1 ] = p r e [ 0 ] + p r e [ 1 ] + … + p r e [ l − 2 ] + p r e [ l − 1 ] pre[l-1]=pre[0]+pre[1]+ \ldots+pre[l-2]+pre[l-1] pre[l1]=pre[0]+pre[1]++pre[l2]+pre[l1]
p r e [ r ] = p r e [ 0 ] + p r e [ 1 ] + … + p r e [ l − 1 ] + p r e [ l ] + p r e [ l + 1 ] … + p r e [ r − 1 ] + p r e [ r ] pre[r]=pre[0]+pre[1]+ \ldots+pre[l-1]+pre[l]+pre[l+1] \ldots+pre[r-1]+pre[r] pre[r]=pre[0]+pre[1]++pre[l1]+pre[l]+pre[l+1]+pre[r1]+pre[r]
p r e [ r ] − p r e [ l − 1 ] = p r e [ l ] + p r e [ l + 1 ] + … + p r e [ r − 1 ] + p r e [ r ] pre[r]-pre[l-1]=pre[l]+pre[l+1]+ \ldots+pre[r-1]+pre[r] pre[r]pre[l1]=pre[l]+pre[l+1]++pre[r1]+pre[r]

输入 :
[ n u m s ] [ nums ] [nums] = [ 1,2,3,4,5,6,7,8,9,10,11 ]
[ f i n d S u m ] [ findSum ] [findSum] = [ [ 1,5 ],[ 6,11 ],[ 1,11 ] ]

输出 :
[ 15,51,66 ]

i n d e x index index01234567891011
[ n u m s ] [ nums ] [nums]1234567891011/
[ p r e f i x S u m ] [ prefixSum ] [prefixSum]01361015212836455566
public void getSum(int[] nums, int[][] findSum)
{
    int[] prefixSum = new int[nums.length + 1];

    for (int i = 1; i < prefixSum.length; i++)
    {
        prefixSum[i] = prefixSum[i - 1] + nums[i - 1];
    }

    for (int[] find : findSum)
    {
        int l = find[0];
        int r = find[1];

        System.out.print(prefixSum[r] - prefixSum[l - 1]+" ");

		//如果 findSum 中的 l 和 r 为原数组下标而不是第 l / r 个数,可以 :
		//int l = find[0] + 1; 例 : 原数组下标 0 对应第 1 个数
		//int r = find[1] + 1;
		//或者 :
		//prefixSum[r +1] - prefixSum[l]
    }
}
补充

[ p r e f i x S u m ] [prefixSum] [prefixSum] 长的度比 [ n u m s ] [nums] [nums] 多 1 是为了设置 p r e f i x S u m [ 0 ] = 0 prefixSum[0]=0 prefixSum[0]=0,然后让 p r e f i x S u m [ 1 ] prefixSum[1] prefixSum[1] 保存 [ n u m s ] [nums] [nums] 的第一个数的前缀和。

因为如果 p r e f i x S u m [ 0 ] prefixSum[0] prefixSum[0] 保存的是 [ n u m s ] [nums] [nums] 第一个数的前缀和,在计算 s u m ( l , r ) sum(l,r) sum(l,r) 的时候需要减去第 l l l 个数的上一个数的前缀和,当 l = 1 l=1 l=1 时,因为 [ p r e f i x S u m ] [prefixSum] [prefixSum] 的第一个数就是 [ n u m s ] [nums] [nums] 第一个数的前缀和,所以在寻找 [ n u m s ] [nums] [nums] 第一个数上一个数的前缀和时就会导致数组越界。

另一种解决方法是在计算 p r e f i x S u m [ r ] − p r e f i x S u m [ l − 1 ] prefixSum[r] - prefixSum[l - 1] prefixSum[r]prefixSum[l1] 前进行判断,如果 l = 1 l=1 l=1 则直接返回 p r e f i x S u m [ r ] prefixSum[r] prefixSum[r],由于每次查询都要多进行一次判断,所以不建议采用这种写法。


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/langs/726939.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-04-26
下一篇2022-04-26

发表评论

登录后才能评论

评论列表(0条)

    保存