费波那契数列(意大利语:Successione di Fibonacci),又译费波拿契数、斐波那契数列、费氏数列、黄金分割数列。php
用文字来讲,就是费波那契数列由0和1开始,以后的费波那契系数就由以前的两数相加。首几个费波那契系数是(OEIS A000045):算法
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946,………………缓存
特别指出:0不是第一项,而是第零项。数据结构
(以上来自维基百科)函数
求解Fibonacci数列用java的递归很简单:递归
public static long fibonacci(int n)
{
if(n == 0 || n == 1)
{
return 1;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}ip
但用递归求解的效率几乎是没法容忍的,当n为50是,估计须要好几分钟,由于每递归调用一次fibonacci()函数,都会从新计算fibonacci(n - 1)和fibonacci(n - 2),这样有不少数都是重复计算的,一个比较简单的方法就是用一个数据结构将计算后的值缓存起来,ci
求解时先从缓存里面拿数据,没有的话再计算并将计算后的结果加到缓存里面,这样就避免了不少重复计算。下面是用HashMap将数据缓存的例子:get
private static HashMap<Integer, Long> hashMap = new HashMap<Integer, Long>();
private static long value;
public static long effectFibonacci(int n)
{
if(n == 0 || n == 1)
{
return 1;
}
if(hashMap.containsKey(n))
{
return hashMap.get(n);
}
else
{
value = effectFibonacci(n - 1) + effectFibonacci(n - 2);
hashMap.put(n, value);
}
return value;
}
这个算法跟上一个的效率相比有了很大的提升,当n = 1500时,花费的时间大约是 3082077 microseconds,而用上一个递归直接算,不知何年才能得出结果。
还有一种求解Fibonacci问题的方法就是利用动态规划算法,动态规划算法是将一个较大的问题分解为若干类似子问题,求解子问题而后合并并获得原问题的解,动态规划算法适用于有重叠子问题和最优子结构性质的问题,重叠子问题即原问题可分解为若干的求解算法类似的子问题,最优子结构就是局部最优致使全局最优,即可以将子问题的解合并后获得原问题的解,这跟贪心算法类似。下面是用动态规划算法求解Fibonacci数列问题:
public static long bestFinabocci(int n)
{
long previous = 1, next = 1;
long tmp = 2;
for (int i = 2; i <= n; i++)
{
tmp = previous + next; //从2开始,每个后面的数都是前面两个数之和
previous = next;
next = tmp;
}
return tmp;
}
跟上一个使用递归缓存求解,动态规划算法在效率上有了很大的提升,一样当 n = 1500是,递归缓存花费的时间大约是 3082077 microseconds,而动态规划花费的时间大约是 40410 microseconds。
由上面的实验来看,在递归的问题上,最好使用循环代替递归,不得不用到递归时,最好将数据缓存起来避免重复计算,不要直接调用递归函数。