递归阶乘程序的复杂性

时间:2010-02-24 15:41:50

标签: complexity-theory factorial

查找数字n的阶乘的递归程序的复杂性是多少?我的预感是它可能是O(n)

4 个答案:

答案 0 :(得分:35)

如果将乘法设为O(1),则是,O(N)是正确的。但请注意,在有限硬件上乘以两个任意长度x的数字 O(1) - 因为x趋于无穷大,乘法所需的时间会增长(例如,如果您使用Karatsuba multiplication,则为O(x ** 1.585))。

理论上你可以用Schönhage-Strassen对数量足够大的数字做得更好,但我承认我没有真正的世界经验。 x,“长度”或“数字位数”(无论以何种为基础,无论如何对N的大O都无关紧要,当然也会随着O(log N)而增长。

如果您的意思是将问题限制为足够短的数字因子乘以O(1),那么N无法“趋于无穷大”,因此大O符号是不合适的。

答案 1 :(得分:19)

当您表达算法的复杂性时,它始终是输入大小的函数。如果您乘以的数字是固定大小,则假设乘法是O(1)操作是有效的。例如,如果要确定计算矩阵乘积的算法的复杂性,可以假设矩阵的各个组件具有固定大小。那么假设两个单独的矩阵分量的乘法是O(1)是有效的,你可以根据每个矩阵中的条目数计算复杂度。

但是,当您想要计算出计算N!的算法的复杂性时,您必须假设N可以任意大,因此假设乘法是{ {1}}操作。

如果你想将一个n位数与一个m位数相乘,那么天真算法(你手工做的那种)需要时间O(1),但算法更快。

如果您想分析用于计算O(mn)

的简易算法的复杂性
N!

然后在for循环中的第k个步骤,您将 factorial(N) f=1 for i = 2 to N f=f*i return f 乘以(k-1)!。用于表示k的位数为(k-1)!,用于表示O(k log k)的位数为k。因此,将O(log k)(k-1)!相乘所需的时间为k(假设您使用了朴素乘法算法)。然后算法所花费的总时间是每个步骤所用时间的总和:

O(k (log k)^2)
 的 sum k = 1 to N [k (log k)^2] <= (log N)^2 * (sum k = 1 to N [k]) =

您可以使用更快的乘法算法来改善此性能,例如Schönhage-Strassen,它需要{n = 2个数字的时间O(N^2 (log N)^2)

提高性能的另一种方法是使用更好的算法来计算O(n*log(n)*log(log(n)))。我所知道的最快的一个首先计算N!的素数因子分解,然后乘以所有素数因子。

答案 2 :(得分:16)

假设你在谈论有史以来最天真的因子算法:

factorial (n):
  if (n = 0) then return 1
  otherwise return n * factorial(n-1)

是的,该算法是线性的,在O(n)时间内运行。这是因为它每次递减值n时执行一次,并且它递减值n直到它达到0,这意味着函数被递归调用n倍。当然,这是假设递减和乘法都是常数运算。

当然,如果你以其他方式实现阶乘(例如,使用递归而不是乘法),最终会得到一个更加时间复杂的算法。不过,我不建议使用这样的算法。

答案 3 :(得分:2)

递归阶乘的时间复杂度为:

factorial (n) {    
    if (n = 0) 
        return 1
    else
        return n * factorial(n-1)
}

所以

一个递归调用的时间复杂度为:

T(n) = T(n-1) + 3   (3 is for As we have to do three constant operations like 
                 multiplication,subtraction and checking the value of n in each recursive 
                 call)

     = T(n-2) + 6  (Second recursive call)
     = T(n-3) + 9  (Third recursive call)
     .
     .
     .
     .
     = T(n-k) + 3k
     till, k = n

     Then,

     = T(n-n) + 3n
     = T(0) + 3n
     = 1 + 3n

以Big-Oh表示法表示,

T(N)与n成正比,

因此, 递归阶乘的时间复杂度为O(n)。 由于递归调用期间没有占用额外的空间,因此空间复杂度为O(N)。