如何在恒定时间内找到给定索引区间(i,j)的元素总和?

时间:2010-03-18 20:23:03

标签: algorithm arrays

给定一个数组。我们如何在恒定时间内找到索引间隔(i, j)中的元素总和。您可以使用额外的空间 例如:
答:3 2 4 7 1 -2 8 0 -4 2 1 5 6 -1
长度= 14

int getsum(int* arr, int i, int j, int len);
// suppose int array "arr" is initialized here
int sum = getsum(arr, 2, 5, 14);

总和应该是恒定时间的10。

5 个答案:

答案 0 :(得分:22)

如果您可以花费O(n)时间来“准备”辅助信息,根据这些信息,您可以在O(1)中计算总和,您可以轻松地完成。

准备(O(n)):

aux[0] = 0;
foreach i in (1..LENGTH) {
  aux[i] = aux[i-1] + arr[i];
}

查询(O(1)),arr1计算到LENGTH

sum(i,j) = aux[j] - aux[i-1];

我认为这是意图,因为,否则,这是不可能的:任何length计算sum(0,length-1)你应该扫描整个阵列;这需要线性时间,至少。

答案 1 :(得分:5)

除非您存储信息,否则无法在固定时间内完成。

你必须做一些事情,比如特别修改数组,为每个索引存储数组开头和这个索引之间所有值的总和,然后在范围上使用减法来得到总和的差值。 / p>

但是,您的代码示例中似乎没有任何内容允许这样做。该数组由用户创建(并且可以随时更改),您无法控制它。

任何需要扫描顺序未排序列表中的一组元素的算法都是O(n)。

答案 2 :(得分:2)

以前的答案对于提出的问题绝对没问题。我只是补充一点,如果这个问题有点像:

Find the sum of the interval, if the array gets changed dynamically.

如果数组元素发生了变化,那么我们必须重新计算我们存储在辅助数组中的任何总和,如@ Pavel Shved方法中所述。 重新计算是O(n)操作,因此我们需要通过使用Segment Tree将复杂度降低到O(nlogn)。

http://www.geeksforgeeks.org/segment-tree-set-1-sum-of-given-range/

答案 3 :(得分:1)

给出[l,r]

,有三种已知的基于范围的查询算法

1.Segment树:总查询时间O(NlogN) 2.Fenwick树:总查询时间O(NlogN) 3.Mo的算法(平方根分解)

前两个算法可以处理给你的列表/数组中的修改。第三种算法或Mo的算法是离线算法,意味着之前需要向您提供所有查询。此算法中不允许对列表/数组进行修改。对于此算法的实现,运行时和进一步阅读,您可以查看此Medium博客。它用代码解释。而且很少有人真正了解这种方法。

答案 4 :(得分:0)

这个问题将解决O(n ^ 2)时间,O(n)空间或O(n)时间,O(n)空间..

现在是这种情况下最佳的最佳解决方案(即O(n)时间,O(n)) 假设给出了一个[] = {1,3,5,2,6,4,9} 如果我们创建一个数组(sum []),其中我们将0索引的和值保存到该特定索引。对于数组a [],sum数组将是sum [] = {1,4,9,11, 17,21,30};像 {1,3 + 1,3 + 1 + 5 ......}这需要O(n)时间和O(n)空间。 当我们给索引然后它直接从sum数组中获取它意味着add(i,j)= sum [j] -sum [i-1];这需要O(1)次和O(1)空格...... 所以,这个程序需要O(n)时间和O(N)空间..

int sum [] = new int [l];

    sum[0]=a[0];
    System.out.print(cumsum[0]+" ");
   for(int i=1;i<l;i++)
   {
       sum[i]=sum[i-1]+a[i];
       System.out.print(sum[i]+" ");
   }  

?*这给出1,4,9,11,17,21,30并且花费O(n)时间和O(n)空格* /

sum(i,j)= sum [j] -sum [i-1] / 这给出了从i到j的索引之和,取O(1)时间和O(1)空间 /

所以,这个程序需要O(n)时间和O(N)空格.. 强调文本