计算阶乘n的时间复杂度是多少!使用Java';s大整数
假设算法如下所示:计算阶乘n的时间复杂度是多少!使用Java';s大整数,java,algorithm,time-complexity,biginteger,factorial,Java,Algorithm,Time Complexity,Biginteger,Factorial,假设算法如下所示: public static BigInteger getFactorial(int num) { BigInteger fact = BigInteger.valueOf(1); for (int i = 1; i <= num; i++) fact = fact.multiply(BigInteger.valueOf(i)); // ? time complexity return fact; } public静态biging
public static BigInteger getFactorial(int num) {
BigInteger fact = BigInteger.valueOf(1);
for (int i = 1; i <= num; i++)
fact = fact.multiply(BigInteger.valueOf(i)); // ? time complexity
return fact;
}
public静态biginger getFactorial(int num){
BigInteger事实=BigInteger.valueOf(1);
对于(int i=1;i而言,fact
中包含的位数是log(fact)
。O(log(n!))==O(nlogn)
,因此n!
中的位数与nlogn
成比例增长。因为您的算法将值堆积到部分积上,而不会将它们拆分为较小的中间值(分治方式),我们可以断言,在计算n!
时,其中一个被乘的数字将小于n
。使用小学乘法,我们有O(logn*nlogn)
时间将这些数字相乘,我们有n-1
倍数,所以这是O(n*logn*nlogn)==O((nlogn)^2
。我确实认为这是小学乘法的一个严格上限,因为尽管开始乘法要小得多,后一半都大于O((n/2)log^2(n/2))
,其中有(n/2)
,所以O((n/2)^2*log^2(n/2))==O((nlogn)^2)
然而,biginger
完全有可能使用Karatsuba乘法、Toom Cook乘法,甚至可能是Schönhage–Strassen算法。我不知道这些算法如何处理大小变化如此大的整数(logn
vsnlogn
),所以我不能给出一个严格的上界。我所能做的就是推测它将小于O(n*F(nlogn))
,其中F(x)
是使用特定算法乘以两个长度数x
。事实中的位数是log(fact)
,而O(log(n!))==O(nlogn)
如前所述。因此,只需应用biginger
使用的任何乘法算法即可。您好@DillonDavis,谢谢,如果biginger使用Karatsuba乘法,加上O(x**1.585),总复杂度是否为O((nlogn)^1.585)?老实说,我不是100%确定。两个相乘的值甚至不接近相同的大小,因此时间可能小于O(x**1.585)
,另一方面,我们进行num
相乘,因此其中可能有另一个因子n
。它肯定是O((n^2logn)^1.585)
,但很可能有一个更严格的上限。事实上,使用小学乘法,我们已经有了O(logn*(nlogn))
,因为其中一个被乘法的数字最多是num
(n
),所以这本身就给出了O((nlogn)^2)
,这比我给你的另一个估计要好。好吧,Java的BigInteger乘法使用Karatsuba、Toom Cook 3路,但还没有Schönhage Strassen。当然还有小值的教科书。如果算法不是“除法和征服法”,那么你会不断地用一个“小”乘以一个快速增长的大数一个是SSSLLLOOWWW。@RudyVelthuis我同意你的最后一点,但是OP问的是factorial.correct的具体实现的时间复杂度。我只是想指出这种天真方法的缺陷。我想告诉你在Java.FWIW中使用哪些算法来乘以大整数。我刚刚意识到t如果其中一个数字低于阈值(并且上面的循环索引远低于阈值),将使用教科书,所以这里根本不使用Karatsuba等。只有教科书,除非你使用分治算法。@RudyVelthuis:我尝试了几种不同的方法来计算阶乘作为答案。安排事情有目的地利用更复杂的算法明显更快。@JamesKPolk关于我们能以多快的速度将素数筛选到n
,使用平方运算(在BigInteger
中的引擎盖下)进行求幂以更快地获得结果可能会更快。
public BigInteger getFactorial2(long n) {
return subFactorial(1, n);
}
private BigInteger subFactorial(long a, long b) {
if ((b - a) < 10) {
BigInteger res = BigInteger.ONE;
for (long i = a; i <= b; i++) {
res = res.multiply(BigInteger.valueOf(i));
}
return res;
} else {
long mid = a + (b - a) / 2;
return subFactorial(a, mid).multiply(subFactorial(mid + 1, b));
}
}