题目描述
大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。n<=39。
时间限制:1秒 空间限制:32768K
C++实现
递归实现
递归:在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储,因此递归次数过多容易造成栈溢出。
常规的递归方法实现:
class Solution {
public:
int Fibonacci(int n) {
if(n <= 1)
return n;
return Fibonacci(n-1) + Fibonacci(n-2);
}
};
因为栈溢出,运行超时。这个方法行不通。于是就考虑尾递归。
尾递归:如果一个函数中所有递归形式的调用都出现在函数的末尾,我们称这个递归函数是尾递归的。当递归调用是整个函数体中最后执行的语句且它的返回值不属于表达式的一部分时,这个递归调用就是尾递归。
尾递归代码实现:
class Solution {
public:
int Fibonacci(int n) {
return TailFibonacci(n, 0, 1);
}
int TailFibonacci(int n, int a, int b) {
if(n == 0) return 0;
if(n == 1) return b;
return TailFibonacci(n-1, b, a+b);
}
};
非递归实现
class Solution {
public:
int Fibonacci(int n) {
if(n == 0) return 0;
if(n == 1) return 1;
int first = 0; //n-2项
int second = 1; //n-1项
int sum = 0; //n项
int i;
for(i = 2; i <= n; i++) {
sum = first + second;
first = second;
second = sum;
}
return sum;
}
或者:
class Solution {
public:
int Fibonacci(int n) {
if(n == 0) return 0;
if(n == 1) return 1;
int first = 0;
int sum = 1;
for(int i = 2; i <= n; i++) {
sum = sum + first;
first = sum - first;
}
return sum;
}
时间复杂度:O(n)
空间复杂度:O(1)
应用
1. 青蛙跳台阶问题:一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个n级台阶总共有多少种跳法?
【分析】
先考虑最简单的情况。如果只有1级台阶,那显然只有一种跳法。如果有2级台阶,那就有两种跳法:一种是分两次跳,每次跳1级;另一种就是一次跳2级。
接着讨论一般情况。把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) = 。也是动态规划的应用。
2. 我们可以用2x1的小矩形横着或竖着去覆盖更大的矩形。请问用8个2x1的小矩形无重叠地覆盖一个2x8的大矩形,总共有多少种方法?
【分析】可以先把2x8的覆盖方法记为f(8)。用第一个2x1的小矩形去覆盖大矩形的最左边时有两种选择:竖着放或横着放。当竖着放的时候,右边还剩下2x7的区域,这种情形下的覆盖方法记为f(7)。接下来考虑横着放的情况。当2x1的小矩形横着放在左上角的时候,左下角必须横着放一个2x1的小矩形,而在右边还剩下2x6的区域,这种情形下的覆盖方法记为f(6),因此f(8) = f(7) + f(6)。这仍然是斐波那契数列。