计算阶乘n的时间复杂度是多少!使用Java的BigInteger

时间:2019-03-07 06:21:11

标签: 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 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));
        }
    }

1 个答案:

答案 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算法。我不知道它们在如此急剧变化的整数(lognnlogn)上的表现如何,所以我不能给它们给出严格的上限。我所能做的最好是推测它会小于O(n*F(nlogn))的情况,其中F(x)是使用特定算法将长度x的两个数字相乘的时间。