题目:
写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项(即 F(N))。斐波那契数列的定义如下:
F(0) = 0, F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。
1.递归算法(不建议使用):
public int fib(int n){
if(n==0){
return 0;
}
if(n<=2&&n>0){
return 1;
}
return fib(n-1)+fib(n-2);
}
- 原理: 把 f(n)f(n) 问题的计算拆分成 f(n-1)f(n−1) 和 f(n-2)f(n−2) 两个子问题的计算,并递归,以 f(0)f(0) 和 f(1)f(1) 为终止条件。
- 缺点: 递归n次,时间复杂度O(2^n),大量重复的递归计算,过程过于繁琐,例如 f(n)f(n) 和 f(n - 1)f(n−1) 两者向下递归需要 各自计算 f(n - 2)f(n−2) 的值。
2.优化递归(利用数组保存重复数字):
public int fib1(int n) {
int[] num=new int[50];
// 结束条件
if(n==0){
return 0;
}
if (n == 1 || n == 2) {
return 1;
}
// 检查数组中有没有计算好的结果,如果有,直接返回结果,如果没有进行计算,并存入数组
// 1如果有,直接返回结果
if (num[n] != 0) {
return num[n];
}
// 2如果没有, 进行计算,并存入数组
int x = fib1( n - 1 ) + fib1( n - 2 );
num[n] = x;
return x;
}
- 原理:利用数组将重复元素保存下来,减少重复递归算法
- 缺点:记忆化存储需要使用 O(N) 的额外空间。
3.动态规划(递归算法)
public int fib2(int n) {
int a = 0, b = 1;
int sum = 0;
for(int i = 0; i < n; i++){
sum = (a + b) % 1000000007;
a = b;
b = sum;
}
return sum;
}
- 时间复杂度 O(N) : 计算 f(n) 需循环 n 次,每轮循环内计算操作使用 O(1)。
- 空间复杂度 O(1) : 几个标志变量使用常数大小的额外空间。
注意:
取模 1e9+7(1000000007)是为了限制最后的结果,防止数据太大无法保存。