记录来自《剑指offer》的算法题。
题目如下:
写一个函数,输入n,实现斐波那契数列的第n项。
斐波那契数列的定义如下:
教科书上通常在介绍递归的时候都会使用斐波那契数列作为例子,然后给出下列解法:
long long Fibonacci(unsigned int n){
if(n<=0)
return 0;
if(n == 1)
return 1;
return Fibonacci(n-1) + Fibonacci(n-2);
}
但这个算法在n的增大后会变得很慢,主要原因是重复的计算比较多,改进算法如下所示:
// 改进版本
long long FibonacciOptimz(unsigned int 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 (unsigned int i = 2; i <= n; i++){
fibN = fibNMinusOne + fibNMinusTwo;
fibNMinusTwo = fibNMinusOne;
fibNMinusOne = fibN;
}
return fibN;
}
// 测试
int main(void){
int n = 10;
cout << "use Fibonacci(), n = " << n << ", result = " << Fibonacci(n) << endl;
cout << "use FibonacciOptimz(), n = " << n << ", result = " << FibonacciOptimz(n) << endl;
cout << "start to test:\n";
int test[] = { 0, 1, 2, 3, 5, 10, 40, 50, 100 };
for (int i = 0; i < 9; i++){
int num = test[i];
cout << "use FibonacciOptimz(), num = " << num << ", result = " << FibonacciOptimz(num) << endl;
}
system("pause");
return 0;
}
这种算法的时间复杂度是 O(n) ,它采用循环的方法,每次循环的时候都保存中间值,并用于下次的计算。
对于斐波那契数列的应用,还有如下问题:
一只青蛙一次可以跳上一级台阶,也可以跳上2级台阶。求该青蛙跳上一个n级的台阶总共有多少种跳法。
这个问题也就是需要实现斐波那契数列。考虑最简单的情况,如果只有1级台阶,那显然只有一种跳法;如果有2级台阶,则有两种跳法,一次只跳1级和1次跳两级台阶。现在讨论一般情况,将n级台阶时的跳法看成是n的函数,记为 f(n) 。当 n>2 时,第一次跳的时候有两种选择,一是第一次只跳1级,此时跳法数目等于后面剩下的n-1级台阶的跳法数目,即 f(n−1) ;另一种选择是第一次跳2级,此时跳法数目等于后面剩下的n-2级台阶的跳法数目,即为 f(n−2) 。因此n级台阶的不同跳法的总数 f(n)=f(n−1)+f(n−2) ,也就是斐波那契数列。
当然,如果上述问题的条件变成:青蛙一次可以跳上1级台阶,也可以跳上2级 ⋯⋯ 它也可以跳上n级,问跳上n级台阶总共有多少种跳法。通过数学归纳法可以得到 f(n)=2n−1 。