记录来自《剑指offer》的算法题。
题目如下:
写一个函数,输入n,实现斐波那契数列的第n项。
斐波那契数列的定义如下:
f(n)=⎧⎩⎨01f(n−1)+f(n−2)n=0n=1n>1
教科书上通常在介绍递归的时候都会使用斐波那契数列作为例子,然后给出下列解法:
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。