【问题标题】:Big O, what is the complexity of summing a series of n numbers?大O,对一系列n个数字求和的复杂度是多少?
【发布时间】:2012-03-04 09:42:32
【问题描述】:

我一直认为的复杂性:

1 + 2 + 3 + ... + n 是 O(n),将两个 n × n 矩阵相加将是 O(n^2)。

但今天我从一本教科书中读到,“根据前 n 个整数之和的公式,这是 n(n+1)/2”,然后是:(1/2)n^2 + (1 /2)n,因此 O(n^2)。

我在这里缺少什么?

【问题讨论】:

  • 了解“this”是什么会有所帮助。你是对的,加起来 n 件事(做 n 次,每件事的成本 O(1))是 O(n)。但是,如果不是添加 1+2+3+ 等,您必须 do 一次,然后 do 两次,然后 3 次,等等,然后在 1 +2+3..+n 完成了,你已经完成了 n*(n+1)/2 件事,即 O(n^2)。
  • 失踪?好吧,您找到了解释它的求和公式。您还需要什么帮助?
  • @DSM 抱歉含糊不清,“this”指的是1 + 2 + 3 + ... + n
  • @user1032613:所以要明确一点,“然后是这样”是您的亮点,而不是书中所说的?因为如果是这样,那么我认为下面的几个答案是正确的,并且您将通常对 n 数字求和的算法的复杂性与 它发生 我们可以计算总和这一事实混淆了1+2+..+n 使用公式。假设我们将 n 个平方相加,而不是 1+4+9+...n^2。它们的总和将是 (n)(n+1)(2n+1)/6,但这并不意味着将 n 个事物加在一起会变成 O(n^3);相反,这意味着在特殊情况下,我们可以在 O(1) 中得到它。

标签: performance algorithm optimization complexity-theory big-o


【解决方案1】:

big O notation 可用于确定任何函数的增长率。​​p>

在这种情况下,这本书似乎不是在讨论计算值的时间复杂度,而是在讨论值本身。而n(n+1)/2 就是O(n^2)

【讨论】:

  • 我在教科书 Karumanchi 中读到 1+2+3+...+k = k(k+1)/2 >n => k=O(√n)。这是怎么发生的。你能向我解释一下吗...谢谢
【解决方案2】:

您混淆了运行时的复杂性和结果的大小(复杂性)。

求和的运行时间,一个接一个,前n个连续数确实是O(n i>).1

但是结果的复杂度,即“sum from 1 to n”的大小 = n(n – 1) / 2 是 O(n ^ 2)。


1 但是对于任意大的数字,这很简单,因为添加大数字比添加小数字需要更长的时间。对于精确的运行时分析,您确实必须考虑结果的大小。然而,这通常与编程无关,甚至在纯理论计算机科学中也无关。在这两个域中,对数字求和通常被认为是 O(1) 操作,除非域另有明确要求(即在为 bignum 库实现操作时)。

【讨论】:

  • "前n个连续数相加的运行时间确实是O(n)" - 不,是n任意数相加的运行时间。前n个连续数求和的运行时间是应用公式n*(n+1)/2的运行时间,即O(1)。 :)
  • @Serge No.“将前 n 个连续数字相加”是一个算法描述。将其与“前 n 个连续数字的总和”进行对比。后者关心结果。前者与方法有关,即将整数一一相加。不过,我可能会更明确地说……
  • 当然这是一个术语问题。而且由于它不是正式的描述,而只是对话,因此可能取决于上下文。但在大多数情况下,在对话期间“对前 n 个连续数字求和”或类似的不是算法 - 它是一个任务(要解决的问题)。不是任何特定的实现(算法)来解决这个任务,而是任务本身。谈论任务的时间复杂度就是谈论解决它的最佳算法的时间复杂度(在谈话中,因为严格来说只有算法可能有运行时间)。
【解决方案3】:

n(n+1)/2 是对连续的 N 个整数序列求和的快速方法(从 1 开始)。我认为您将算法与大哦符号混淆了!

如果你把它看成一个函数,那么这个函数的大复杂度就是 O(1):

公共 int sum_of_first_n_integers(int n) { 返回 (n * (n+1))/2; }

简单的实现将具有 O(n) 的大复杂度。

public int sum_of_first_n_integers(int n) {
  int sum = 0;
  for (int i = 1; i <= n; i++) {
    sum += n;
  }
  return sum;
}

即使只是查看单个 n×n 矩阵的每个单元格也是 O(n^2),因为矩阵有 n^2 个单元格。

【讨论】:

  • 我认为这并不能解释实际被问到的问题:“为什么前 n 个整数的总和是 O(n^2)”?
  • 第一个函数的复杂度不是 O(1)。两个 n 位数字的乘法需要 n^2 时间。第二个函数也不需要 O(n) 时间。对于较大的 N 值,加法是线性运算。
【解决方案4】:

实际上并不是问题的复杂性,而是算法的复杂性。

在您的情况下,如果您选择遍历所有数字,则复杂性确实是 O(n)

但这不是最有效的算法。一种更有效的方法是应用公式 - n*(n+1)/2,它是常数,因此复杂度为 O(1)

【讨论】:

    【解决方案5】:

    所以我的猜测是,这实际上是对Cracking the Coding Interview 的引用,它在StringBuffer 实现上有这段:

    在每次连接时,都会创建一个字符串的新副本,并且 两个字符串被逐个字符地复制过来。首先 迭代要求我们复制x 个字符。第二次迭代 需要复制2x 个字符。第三次迭代需要3x,并且 很快。因此总时间为O(x + 2x + ... + nx)。这减少了 到O(xn²)。 (为什么不是O(xnⁿ)?因为1 + 2 + ... n等于n(n+1)/2 或者,O(n²)。)

    无论出于何种原因,我在第一次通读时也发现这有点令人困惑。要看到的重要一点是nn 相乘,或者换句话说 正在发生,并且占主导地位。这就是为什么 O(xn²) 最终只是 O(n²) —— x 有点像红鲱鱼。

    【讨论】:

    • “n² 正在发生,这占主导地位”整个事情“点击”,谢谢!
    【解决方案6】:

    您有一个不依赖于添加数字数量的公式,因此它是一个恒定时间算法,或 O(1)。

    如果你一次将每个数字加一个,那么它确实是 O(n)。公式是捷径;这是一种不同的、更有效的算法。当添加的数字都是 1..n 时,快捷方式有效。如果你有一个不连续的数字序列,那么捷径公式就不起作用,你必须回到逐一算法。

    不过,这些都不适用于数字矩阵。要添加两个矩阵,仍然是 O(n^2),因为您要添加 n^2 个不同的数字对以获得 n^2 个结果的矩阵。

    【讨论】:

      【解决方案7】:

      对 N 个任意整数求和与对 N 个连续的整数求和是有区别的。对于 1+2+3+4+...+N,您可以利用这样一个事实,即它们可以分成具有共同总和的对,例如1+N = 2+(N-1) = 3+(N-2) = ... = N + 1。所以这是 N+1,N/2 次。 (如果有一个奇数,其中一个将是不成对的,但稍加努力你就会发现在这种情况下同样的公式成立。)

      不过,这不是 O(N^2)。这只是一个使用 N^2 的公式,实际上是O(1)。 O(N^2) 意味着(大致)计算它的步数会像 N^2 一样增长,对于大 N。在这种情况下,无论 N 多少,步数都是相同的。

      【讨论】:

        【解决方案8】:

        将前 n 个数字相加:

        考虑算法:

        Series_Add(n)
        
           return n*(n+1)/2
        

        这个算法确实在O(|n|^2)中运行,其中|n|是 n 的长度(位)而不是大小,这仅仅是因为 2 个数字的乘法,k 位中的一个和 l 位中的另一个在 O(k*l) 时间内运行。 p>

        小心

        考虑这个算法:

        Series_Add_pseudo(n):
           sum=0   
           for i= 1 to n:
              sum += i
           return sum
        

        这是一种天真的方法,您可以假设该算法在线性时间或通常在多项式时间内运行。事实并非如此。

        n 的输入表示(长度)是 O(logn) 位(除了一元之外的任何 n 元编码),并且算法(尽管它在幅度上线性运行)它运行 指数 (2^logn) 输入的长度。 这实际上是伪多项式算法的情况。它似乎是多项式,但实际上不是。

        您甚至可以在 python(或任何编程语言)中尝试使用中等长度的数字,例如 200 位。

        应用第一个算法,结果会在一瞬间出现,而应用第二个算法,你必须等待一个世纪......

        【讨论】:

          【解决方案9】:

          1+2+3+...+n 总是小于 n+n+n...+n n 次。你可以将这个 n+n+..+n 重写为 n*n。

          f(n) = O(g(n)) 如果存在一个正整数 n0 和一个正整数 常数 c,使得 f(n) ≤ c * g(n) ∀ n ≥ n0

          因为 Big-Oh 表示函数的上界,其中函数 f(n) 是直到 n 的自然数之和。

          现在,谈到时间复杂度,对于小数,加法应该是一个恒定的工作量。但是 n 的大小可能很大;你不能否认这种可能性。

          adding integers can take linear amount of time when n is really large.。所以你可以说加法是 O(n) 操作并且你正在添加 n 项。所以仅此一项就可以使它成为O(n ^ 2)。当然,它并不总是需要 n^2 时间,但当 n 非常大时,这是最坏的情况。 (上限,记得吗?)


          现在,假设您直接尝试使用 n(n+1)/2 来实现它。一乘一除,这应该是常数运算吧? 没有。

          使用自然大小的位数度量,使用长乘法将两个 n 位数相乘的时间复杂度为 Θ(n^2)。当用软件实现时,长乘法算法必须处理加法期间的溢出,这可能很昂贵。 Wikipedia

          这又把我们留给了 O(n^2)。

          【讨论】:

            【解决方案10】:

            它等价于 BigO(n^2),因为它等价于 (n^2 + n) / 2 而在 BigO 中你忽略了常数,所以即使 n 的平方除以 2,你仍然有指数增长以平方的速率。

            想想 O(n) 和 O(n/2) 吗?我们同样不区分两者,O(n/2) 对于较小的 n 只是 O(n),但增长率仍然是线性的。

            这意味着随着 n 的增加,如果您要在图表上绘制操作数,您会看到一条 n^2 曲线。

            你已经可以看到了:

            when n = 2 you get 3
            when n = 3 you get 6
            when n = 4 you get 10
            when n = 5 you get 15
            when n = 6 you get 21
            

            如果你像我在这里那样绘制它:

            你看到曲线类似于n^2的曲线,你会在每个y处有一个较小的数字,但曲线与它相似。因此我们说量级是相同的,因为随着 n 的增大,它的时间复杂度会增加,类似于 n^2。

            【讨论】:

              【解决方案11】:

              n个自然数系列之和的答案可以用两种方法找到。第一种方法是在循环中添加所有数字。在这种情况下算法是线性的,代码会是这样的

               int sum = 0;
                   for (int i = 1; i <= n; i++) {
                   sum += n;
                 }
               return sum;
              

              类似于 1+2+3+4+......+n。在这种情况下,算法的复杂度计算为执行加法运算的次数,即 O(n)。

              求n个自然数级数之和的第二种方法是最直接的公式n*(n+1)/2。这个公式使用乘法而不是重复加法。乘法运算具有非线性时间复杂度。有多种算法可用于乘法,其时间复杂度从 O(N^1.45) 到 O(N^2)。因此,在乘法的情况下,时间复杂度取决于处理器的架构。但出于分析目的,乘法的时间复杂度被认为是 O(N^2)。因此,当使用第二种方法求和时,时间复杂度将为 O(N^2)。

              这里的乘法运算与加法运算不同。如果有人了解计算机组织主题,那么他可以很容易地理解乘法和加法运算的内部工作。乘法电路比加法电路更复杂,计算结果需要比加法电路更长的时间。所以序列和的时间复杂度不能恒定。

              【讨论】:

              • 我认为您将操作数与数字中的位数混淆了。如果将 n 设置为操作数,则在第一种情况下,您必须执行 n 求和,因此复杂度为 O(n)。在第二种情况下,成本将为 O(1),因为您实际上正在执行已知且固定数量的操作(本公式中为 3)。
              猜你喜欢
              • 2019-07-27
              • 1970-01-01
              • 2011-06-01
              • 1970-01-01
              • 1970-01-01
              • 2021-05-13
              • 1970-01-01
              • 2020-07-15
              • 1970-01-01
              相关资源
              最近更新 更多