单说斐波那契数列
我们熟悉的斐波那契数列的问题即:
- 写一个函数,输入 n , 求斐波那契数列的第 n 项 。
- 斐波那契数列的定义如下
0 n=0
f(n) = 1 n=1
f(n-1)+f(n-2) n>1
挑剔的面试官不会喜欢的解法,效率很低
代码:
long long Fibonacci1(const unsigned n){
if(n<= 0 ) return 0;
if(n==1) return 1;
return Fibonacci1(n-1)+Fibonacci1(n-2);
}
我们乍一看我们刚学习斐波那契数列的时候就是这种解题思路,我们几乎非常快就能写出这个函数
但是面试官会告诉你:
来啊,我们来看一下 输入 n = 10 的递归过程
f(10)
/ \
f(9) f(8)
/ \ / \
f(8) f(7) f(7) f(6)
.....................继续分解下去
我们不难发现,重复递归计算的次数越来越多,因此效率很低,面试官不喜欢,我们来介绍下一种优化递归的解法。
面试官期待的解法1:记忆化数组优化重复计算
思路:利用数组记录斐波那契数列中已经计算出的数列项值,之后重复调用时,直接返回记忆的数列项值,这样就会避免重复递归计算。
所需条件:记忆化数组 memo
代码:
const unsigned n= 100; //输入的n
int memo[n+2]; //定义记忆化数组
void InitMemoArr(int arr[]){
memset(arr,-1,n); //将数组元素的初始值设置为-1
arr[0] = 0;
arr[1] = 1;
}
long long Fibonacci2(const unsigned n) {
InitMemoArr(memo);
if(memo[n]!=-1) return memo[n];
return memo[n]=Fibonacci2(n-1)+Fibonacci2(n-2);
}
面试官期待的解法2:直接利用循环过程累加计算
思路: 我们利用 f(1)和f(2)能计算出 f(3) …以此循环类推能得出第 n 项。
所需条件:
例如:求 4 项的值
f (2) = f(1) + f(0)
f (3) = f(2) + f(1)
f (4) = f(3) + f(2)
我们利用 3个变量:fibNminusOne,fibNminusTwo,fibN, 关系如下:
fibN = fibNminusOne+fibNminusTwo;
当得出新的 fibN 后,fibNminusOne,fibNminusTwo,fibN转换关系如下:
fibN = fibNminusOne+fibNminusTwo;
//新 fibN 得出后,为fibNminusOne,fibNminusTwo重新赋值,即递增项数值
fibNminusTwo = fibNminusOne;
fibNminusOne = fibN;
这样循环后就能得出 第 n 项的值(fibN)了
代码:
long long Fibonacci3(const unsigned n){
int result[2] = {0,1};
if(n<2)
return result[n];
long long fibNminusOne = 1; //递推的第一项
long long fibNminusTwo = 0;
long long fibN = 0;
for (int i = 2; i <=n ; ++i) {
fibN = fibNminusOne+fibNminusTwo;
fibNminusTwo = fibNminusOne;
fibNminusOne = fibN;
}
return fibN;
}