1-Description
大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。n<=39
2-Solution
1-问题分析
我们知道Fibonacci数列的定义可以用如下的公式表示:
F
i
b
(
n
)
=
{
0
,
n = 0
1
,
n =1
F
i
b
(
n
−
1
)
+
F
i
b
(
n
−
2
)
,
n>1
Fib(n) = \begin{cases}0,&\text{n = 0} \\1,&\text{n =1} \\Fib(n-1) + Fib(n-2),&\text{n>1} \end{cases}
Fib(n)=⎩⎪⎨⎪⎧0,1,Fib(n−1)+Fib(n−2),n = 0n =1n>1
当然可以很快的将公式转为如下的代码:
class Solution {
public:
int Fibonacci(int n) {
if(n == 0) return 0;
if(n == 1) return 1;
return Fibonacci(n-1) + Fibonacci(n-2);
}
};
但是这样的递归解法在当n很大的时候,会因为计算超时而不能被ac
递归版的fib()低效的根源在于各递归实例均被重复调用,下图以计算fib(5)为例(其中数字均表示计算该数的斐波那契数,下同),可以看出来有非常多的重复调用
针对上述的递归所带来的超时问题可以采用2中方法进行解决:
- 解决方法A(记忆:memoization):将已计算过实例的结果制表备查,避免重复调用
- 解决方法B(动态规划:dynamic programingg)颠倒计算方向:由自顶而下递归变为自底而上迭代,可以用下图表示,需要注意的就是每一项的值都是依靠前两项的结果算出来的,所以自底上下迭代可以很方便的解决本问题
2-代码解决
依据上述分析,可以用下面的代码实现:
- memoization方法
class Solution {
public:
// const int N = 99;
double memo[99];//将已经算得的结果制表备查
int Fibonacci(int n) {
if(n < 2) return n;
if(memo[n]) return memo[n];//如果已经有计算结果,则直接返回表里的值
else return memo[n] = Fibonacci(n-1) + Fibonacci(n-2);//常规递归算法
}
};
- dynamic programin
class Solution {
public:
int Fibonacci(int n) {
int f = 1;//相当于fib(-1)
int g = 0;//fib(0)
while( 0 < n--){
g = g + f;//得到新的计算结果
f = g - f;//f被赋作上一次的g
}
return g;
}
};