【问题标题】:How to find sum of elements from given index interval (i, j) in constant time?如何在恒定时间内从给定的索引间隔(i,j)中找到元素的总和?
【发布时间】:2010-03-18 20:23:02
【问题描述】:

给定一个数组。我们如何在常数时间内找到索引区间(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 在恒定时间内。

【问题讨论】:

  • 现在在O(log N) 中执行此操作,如果您还可以在查询之间更改元素的值:)。
  • int getsum(int* arr, int i, int j, int len) { return 10; } ;)
  • @Matt - 您的恒定时间版本非常慢。它应该是#define getsum(arr, i, j, len) 10 以获得最大效率。
  • @:IVlad 只有在每次元素值更改时给我O(log N) 时间!

标签: algorithm arrays


【解决方案1】:

如果您可以花费 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),您应该扫描整个数组;这至少需要线性时间。

【讨论】:

  • 我认为应该是 aux[j] - aux[i-1]。
  • @Lluis,如果我们从 1 开始计算数组(就是这种情况),那么它应该。
  • 我正在尝试调整它以使用二维数组,但我不知道要更改什么,您介意启发我吗?
  • @DanielBo 当然。在一维情况下,区间有两个边界点,我们使用每个边界记录的“从开始到这里的总和”。在二维情况下(矩形)有多少个边界点有一个区间,“从开始到这里的总和”是什么意思?
【解决方案2】:

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

您必须做一些事情,比如专门修改数组,以便为​​每个索引存储数组开头和该索引之间所有值的总和,然后在范围上使用减法来获得总和的差。

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

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

【讨论】:

  • 是的,在加起来少于 15 个整数的情况下 :-)
  • 您不需要为 14 整数数组存储 105 个整数。您可以通过累加和减法来解决问题。
  • @David,见第 3 段,我已经介绍过了(Pavel 也是如此,以更清晰的方式)。但这仍然是不可能的除非你可以控制数组。否则,您必须在每次调用函数时预先计算值,此时您可能根本不进行预先计算。
  • @paxdiablo:完全理解,但为什么是第二段?这就是吸引我眼球的地方。除此之外,这是一个很好的答案。
  • @David,这是我的第一个想法,我经常为了繁荣而离开大脑f*rts :-) 当我有更多机会考虑时,第三段被添加到编辑中它(这里是凌晨4点,我只是因为孩子们做噩梦,所以我可能有点累)。我会摆脱它,不过现在它与 Pavel 的差别不大。
【解决方案3】:

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

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/

【讨论】:

    【解决方案4】:

    给定 [l,r] 的基于范围的查询的三种已知算法

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

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

    【讨论】:

      【解决方案5】:

      这个问题将解决 O(n^2)time,O(n)space 或 O(n)time,O(n)space..

      现在这种情况下的最佳最优解(即 O(n)time,O(n)) 假设给定 a[]={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) 空间..强调文本

      【讨论】:

        猜你喜欢
        • 2023-04-05
        • 1970-01-01
        • 2016-11-12
        • 2016-08-12
        • 1970-01-01
        • 1970-01-01
        • 2013-08-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多