BigInteger更有效的Fibonacci

时间:2017-02-02 06:10:35

标签: java performance recursion dynamic fibonacci

我正在开发一个类项目,以创建比Fib(n-1) + Fib(n-2)的递归版本更高效的Fibonacci。对于这个项目,我需要使用BigInteger。到目前为止,我已经有了使用地图存储以前的原始数字的想法。

public static BigInteger theBigFib(BigInteger n) {

    Map<BigInteger, BigInteger> store = new TreeMap<BigInteger, BigInteger>(); 

    if (n.intValue()<= 2){
        return BigInteger.ONE;

    }else if(store.containsKey(n)){         
        return store.get(n);    

    }else{
        BigInteger one = new BigInteger("1");
        BigInteger two = new BigInteger("2");
        BigInteger val = theBigFib(n.subtract(one)).add(theBigFib(n.subtract(two)));
        store.put(n,val);           
        return val;
    }

} 

我认为地图的存储量应该超出预期。我也认为这一行

BigInteger val = theBigFib(n.subtract(one)).add(theBigFib(n.subtract(two)));

是一个问题。如果有人能够解释我做错了什么或可能的另一种解决方案,使其比基本代码更快。 谢谢!

2 个答案:

答案 0 :(得分:3)

您不需要以前的所有BigIntegers,只需要最后一次2

您可以使用循环代替递归解决方案。

public static BigInteger getFib(int n) {
    BigInteger a = new BigInteger.ONE;
    BigInteger b = new BigInteger.ONE;

    if (n < 2) {
        return a;
    }
    BigInteger c = null;
    while (n-- >= 2) {
        c = a.add(b);
        a = b;
        b = c;
    }
    return c;
}

如果要存储所有以前的值,可以使用数组。

static BigInteger []memo = new BigInteger[MAX];
public static BigInteger getFib(int n) {
    if (n < 2) {
        return new BigInteger("1");
    }

    if (memo[n] != null) {
        return memo[n];
    }

    memo[n] = getFib(n - 1).add(getFib(n - 2));
    return memo[n];
}

如果您只是希望第n个Fib值快速有效。

您可以使用斐波那契的matrix form

A = 1 1
    1 0

A^n = F(n + 1) F(n)
      F(n)     F(n - 1)

您可以使用Exponentiation by Squaring高效计算A ^ n。

答案 1 :(得分:0)

我相信您的代码中的主要问题是您在每个函数调用上创建一个新的Map。请注意,它仍然是局部变量,尽管您的方法是static。因此,您可以保证store.containsKey(n)条件永远不会成立,您的解决方案并不比天真更好。即它仍具有n的指数复杂性。更准确地说,需要大约F(n)个步骤才能得到答案(主要是因为构成答案的所有“那些”都是通过某些函数调用返回的。)

我建议将变量设为static字段而不是局部变量。然后调用次数应变为线性而非指数,您将看到显着改善。其他解决方案包括带有三个变量的for循环,迭代计算从0,1,2到n的斐波那契数,并且我知道的最佳解包括矩阵求幂或带有实数的显式公式(这是这对精确度不好),但这是一个更适合计算机科学StackExchange网站的问题,imho。