您的位置:首页 > 职场人生

《剑指Offer》学习笔记--面试题9:斐波那契数列

2015-05-06 17:05 555 查看
题目一:写一个函数,输入n,求斐波那契(Fibonacci)数列的第n项。斐波那契数列数列的定义如下:

公式f
=f[n-1]+f[n-2],且f[1]=1,f[2]=1。


效率很低的递归算法,面试官都不会喜欢

long long Fibonacci(unsigned int n)
{
if(n <= 0){
return 0;
}
if(n == 1){
return 1;
}
return Fibonacci(n-1) + Fibonacci(n-2);
}
我们的教科书上反复用这个问题来讲解递归函数,并不能说明递归的解法最适合这道题目。

面试官期待的使用解法

其实改进的方法并不复杂。上述递归代码之所以慢是因为重复计算太多,我们只要想办法避免重复计算就行了。比如我们可以把已经得到的数列中间项保存起来,如果下次需要计算的时候我们先查找一下,如果前面已经计算过就不用再重复计算了。

更简单的方法是从下网上算,首先根据f(0)和f(1)算出f(2),再根据f(1)和f(2)算出f(3).......以此类推就可以算出第n项了。很容易理解,这种思路的时间复杂度是O(n)。

实现代码如下:

#include <iostream>
using namespace std;

long long Fibonacci(unsigned n)
{
int result[2] = {0,1};
if(n < 2)
return result
;
long long fibNMinusOne = 1;
long long fibNMinusTwo = 0;
long long fibN = 0;
for(unsigned int i = 2; i <= n; i++){
fibN = fibNMinusOne + fibNMinusTwo;

fibNMinusTwo = fibNMinusOne;
fibNMinusOne = fibN;
}
return fibN;
}
int main()
{
int n;
while(cin>>n){
cout<<Fibonacci(n)<<endl;
}
system("pause");
return 0;
}
时间复杂度O(logn)但不够实用的解法

矩阵快速幂求Fibonacci。

代码如下:

#include <iostream>
using namespace std;

const int MOD = 19999997;
struct matrix{       //重载结构体
public:
long long a;
long long b;
long long c;
long long d;
matrix &operator * (matrix &data){ //重载*
long long tempa = a;
long long tempb = b;
long long tempc = c;
long long tempd = d;
a = tempa*data.a%MOD+tempb*data.c%MOD;
b = tempa*data.b%MOD+tempb*data.d%MOD;
c = tempc*data.a%MOD+tempd*data.c%MOD;
d = tempc*data.b%MOD+tempd*data.d%MOD;
return *this;
}
matrix &operator = (matrix &data){  //重载&
a = data.a;
b = data.b;
c = data.c;
d = data.d;
return *this;
}
};

long long fastFibonacci(long n)
{
matrix res = {1,1,1,0};
matrix base = {1,1,1,0};
matrix temp;
n++;
while(n){
if(n&1){
res = res*base;
}
temp = base;
base = base*temp;
n >>=1;
}
return res.d;
}
int main()
{
long n;
while(cin>>n){
cout<<fastFibonacci(n)%MOD<<endl;
}
system("pause");
return 0;
}
解法比较

用不同的方法求解斐波那契数列的时间效率大不相同。第一种基于递归的解法虽然直观但是时间效率很低,在实际软件开发中不会用这种方法,也不可能得到面试官的青睐。第二种方法把递归的算法用循环实现,极大地提高了时间效率。第三种方法把斐波那契数列转换成求矩阵的乘方,是一种很有创意的算法。虽然我们可以用O(logn)求得矩阵的n次方,但由于隐含的时间常数较大,很少会有软件采用这种算法。另外实现这种解法的代码也很复杂,不太适用面试。因此第三种方法不是一种实用的算法,不过应聘者可以用它来展现自己的知识面。

除了面试官直接要求编程实现斐波那契数列之外,还有不少面试题可以看成是斐波那契数列的应用,比如:

题目二:一只青蛙可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级台阶总共有多少种跳法。

首先我们考虑最简单的情况。如果只有一级台阶,那显然只有一种跳法。如果有2级台阶,那就有两种跳法了:一种是分两次跳,没跳1级;另外一种就是一次跳2级。

接着我们再来讨论一般情况。我们把n级台阶时的跳法看成时n的函数,记为f(n)。当n>2时,第一次跳的时候就有两种不同的选择:

(1)第一次只挑1级,此时跳法数目等于后面剩下的n-1级台阶的跳法数目,即为f(n-1);

(2)选择第一次跳两级,此时跳法数目等于后面剩下的n-2级台阶的跳法数目,即为f(n-2)。

因此n级台阶的不同跳法的总数f(n) = f(n-1) + f(n-2)。分析到这里我们不难看出这实际上就是斐波那契数列了。

类似的题目还有骨牌覆盖问题,参见我的另一篇博文:算法-骨牌覆盖问题(矩阵快速幂求Fibonacii)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: