9种求斐波那契数(Fibonacci Numbers)的算法
By Long Luo
斐波那契数列( \(\textit{Fibonacci Sequence}\) ) 1,又称黄金分割数列,因数学家莱昂纳多·斐波那契( \(\textit{Leonardoda Fibonacci}\) ) 2 以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:
\(0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233 \dots\)
这个数列从第 \(3\) 项开始,每一项都等于前两项之和。
斐波那契数的边界条件是 \(F(0)=0\) 和 \(F(1)=1\)。当 \(n>1\) 时,每一项的和都等于前两项的和,因此有如下递推关系:
\[ F(n)=F(n-1)+F(n-2) \]
算法一:暴力法
如果不需要求解特别大的数值,又对时间敏感的话,可以有投机取巧的方法:1
2
3
4
5
6
7
8
9
10
11
12class Solution {
int[] fib_nums = {
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181,
6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040,
1346269, 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986,
102334155, 165580141, 267914296, 433494437, 701408733, 1134903170, 1836311903
};
public int fib(int n) {
return fib_nums[n];
}
};
复杂度分析
- 时间复杂度: \(O(1)\)
- 空间复杂度: \(O(n)\)
算法二: 递归(recursion)
显而易见斐波那契数列存在递归关系,很容易想到使用递归方法来求解:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public class Solution {
public static int fib(int n) {
if (n <= 1) {
return n;
}
return fib(n - 1) + fib(n - 2);
}
public static void main(String[] args) {
System.out.println("1 ?= " + fib(1));
System.out.println("1 ?= " + fib(2));
System.out.println("2 ?= " + fib(3));
}
}
复杂度分析:
- 时间复杂度:\(T(n)=T(n-1)+T(n-2)\),可见是指数级的。
我们可以写出其实现递归树,如下所示:1
2
3
4
5
6
7
8
9 fib(5)
/ \
fib(4) fib(3)
/ \ / \
fib(3) fib(2) fib(2) fib(1)
/ \ / \ / \
fib(2) fib(1) fib(1) fib(0) fib(1) fib(0)
/ \
fib(1) fib(0)
可以看出其做了很多重复性的计算,因此对于数值比较大时,其性能是灾难性的。
- 空间复杂度:\(O(n)\) ,函数递归栈。