我正在开发一个类项目,以创建比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)));
是一个问题。如果有人能够解释我做错了什么或可能的另一种解决方案,使其比基本代码更快。 谢谢!
答案 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。