【问题标题】:Running Time of this Simple Program - Time Complexity这个简单程序的运行时间 - 时间复杂度
【发布时间】:2016-08-10 12:44:11
【问题描述】:

我试图弄清楚这个简单程序的时间复杂度是多少,但我似乎不明白什么是最好的方法。

我已经并排写下了每一行的时间复杂度

1    public int fnA (int n) {                   
2      int sum = 0;                    O(1)
3      for (int i = 0; i < n; i++) {   O(n)
4        int j = i;                    O(n)
5        int product = 1;              O(1)
6      
7        while (j > 1) {               O(n)
8          product ∗= j;               O(log n) 
9          j = j / 2;                  O(log n)
10       }
11       sum += product;               O(1)
12     }
13     return sum;                     O(1)
14   }

我是否正确假设这些运行时间并且最终运行时间是:O(n)

如果没有,有人能解释我哪里出错了吗?

总体:

1 + n + n + 1 + n + logn + logn + 1 + 1
= 3n + 2logn + 4

Final: O(n)

【问题讨论】:

    标签: java algorithm time time-complexity big-o


    【解决方案1】:

    首先,您可以计算所有操作。例如:

    1    public int fnA (int n) {                   
    2      int sum = 0;                    1
    3      for (int i = 0; i < n; i++) {   
    4        int j = i;                    n
    5        int product = 1;              n
    6      
    7        while (j > 1) {               
    8          product ∗= j;               ?
    9          j = j / 2;                  ?
    10       }
    11       sum += product;               n
    12     }
    13     return sum;                     1
    14   }
    

    现在我们可以进行计数: 总和为:2 + 3n + nlog(n)

    在很多程序中,计数比较复杂,通常有一个突出的高阶项,例如:2+3n+2n2。在谈论性能时,我们真的很关心 n 何时很大,因为当 n 小时,总和仍然很小。当 n 很大时,高阶项会吸引其余项,因此在此示例中 2n2 确实是重要的项。这就是波浪近似的概念。

    考虑到这一点,通常可以快速确定最常执行的代码部分,并使用其计数来表示总体时间复杂度。在 OP 给出的示例中,它看起来像这样:

    for (int i = 0; i < n; i++) {
        for (int j = i; j > 1; j /= 2)
            product *= j;
    }
    

    给出 ∑log2n。通常计数涉及离散数学,我学到的一个技巧是用它替换积分并做 caculus:∫ log2n = nlog(n)

    【讨论】:

      【解决方案2】:

      上述程序的关键是 while 循环,它是定义因素,其余行的复杂度不会超过 O(n),并假设算术运算将在 O(1) 时间内运行。

      while (j > 1) {              
        product ∗= j;             
        j = j / 2;                         
      }
      

      上述循环的运行时间为 O(log(j)) 并且 j 从 1 到 n 不等,所以它的系列...

      -> O(log(1) + log(2) + log(3) + log(4).....log(n))
      -> O(log(1*2*3*4...*n))
      -> O(log(n!))
      
      and O(log(n!)) is equal to O(n log(n))
      

      以上证明请参考this

      【讨论】:

        【解决方案3】:

        该算法的时间复杂度为O(NlogN)

        for 循环执行N 次(从0N)。

        while 循环执行logN 次,因为您每次都将数字除以一半。

        由于您在for 中执行while,因此您正在执行logN 操作N 次,从那里它是O(NlogN)

        你可以假设所有剩余的操作(赋值、乘法、除法、求和)都需要O(1)

        【讨论】:

          【解决方案4】:

          不是每个 i,都有 logn 循环运行,因此对于 n 元素,总复杂度为 nlogn

          既然你知道下面的循环需要 logn 。

          while (j > 1) {              
                  product ∗= j;             
                 j = j / 2;                         
          }
          

          现在每个i 都会执行这个特定的循环。所以这将被执行n 次。所以它变成了nlogn

          【讨论】:

          • 您能详细说明您是如何得到这个答案的吗?
          • @RandomMath :更新了答案。
          • 只是 while 循环 while ( j > 1) 那不是 O(n)
          • @RandomMath :它只是一个循环中的操作,实际上是 O(1)。虽然它运行了 n 次,所以你可以将其视为 O(n)。整个循环是 while (j > 1) { product ∗= j; j = j / 2;正如您在问题中提到的那样,这完全需要登录时间。
          • 技术上,即使是产品 *= j;是 O(1) 操作并且 j = j / 2;这也是 O(1) 操作。但是由于这些操作对于特定的 i 发生 logn 次......所以它成为特定 i 的 logn。由于 i 从 0 循环到 n,因此这个 logn 循环被执行 n 次,使其成为 nlogn。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-10-05
          • 1970-01-01
          • 2021-02-25
          • 2013-10-05
          相关资源
          最近更新 更多