假设算法如下:
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 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));
}
}
答案 0 :(得分:2)
fact
中包含的位数为log(fact)
。 It can be shown就是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)
。
但是,BigInteger
完全有可能使用Karatsuba乘法,Toom-Cook乘法,甚至使用Schönhage–Strassen算法。我不知道它们在如此急剧变化的整数(logn
和nlogn
)上的表现如何,所以我不能给它们给出严格的上限。我所能做的最好是推测它会小于O(n*F(nlogn))
的情况,其中F(x)
是使用特定算法将长度x
的两个数字相乘的时间。