写一个函数,输入 n
,求斐波那契(Fibonacci)数列的第 n
项。斐波那契数列的定义如下:
F(0) = 0, F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
示例 1:
输入:n = 2
输出:1
示例 2:
输入:n = 5
输出:5
提示:
0 <= n <= 100
解题:
方法一:递归
(1)递归:函数自己调用自己
(2)递归的"缺陷":递归到一定程度,会发生"栈溢出"
(3)递归的"时间复杂度":递归总次数*每次递归的次数
(4)递归的"空间复杂度":递归的深度*每次递归空间的大小(注意:"每次递归空间的大小"是个常数,可以基本忽略不计)
递归的"深度":树的高度(递归的过程是一个"二叉树")
- 时间复杂度
假设n对应复杂度T(n),由于if( n <= 1 )执行1次,f(n-1)执行1次,f(n-2)执行1次,然后f(n-1)和f(n-2)执行一次,因此有T(n)=T(n-1)+T(n-2)+4,忽略次要项,得到T(n)=T(n-1)+T(n-2),根据数学知识可得通项式为
下面继续分析下,不通过数学计算,估算其上下极限
上限:令T(n-2)约等于T(n-1),则T(n)=T(n-1)+T(n-2)=2T(n-1)=2*2*T(n-2)=....=2^n*T(0)=2^n,即为O(2^n)
下限:令T(n-1)约等于T(n-2),则T(n)=T(n-1)+T(n-2)=2T(n-2)=2*2*T(n-4)=....=2^(n/2)*T(0)=2^(n/2),即为O(2^(n/2))
所以最后可得到结果,其时间复杂度结果位于O(2^(n/2))和O(2^n)之间
- 空间复杂度
跟所有递归调用一样,每次调用一次,都会进行压栈操作,因此下面分析函数调用时栈空间情况,要求f(n)会执行f(n-1)+f(n-2)需要压栈一次,然后求f(n-1)会执行f(n-2)+f(n-3)需要压栈一次,....,最后直到到f(1),这里以f(5)为例,那么栈情况如下图所示
递归算法的空间复杂度:递归的深度*每次递归所需的辅助空间的个数。
而树的高度即为递归的深度。
则易知空间复杂度为O(n)。
class Solution {
public:
int fib(int n) {
if(n==0) return 0;
if(n==1) return 1;
return (fib(n-1)+fib(n-2))%1000000007;
}
};
方法二:动态规化法
动态规划过程是:每次决策依赖于当前状态,又随即引起状态的转移。一个决策序列就是在变化的状态中产生出来的,所以,这种多阶段最优化决策解决问题的过程就称为动态规划(DP)。
时间复杂度O(n),空间复杂度O(1)
class Solution {
public:
int fib(int n) {
if(n==0) return 0;
int func1=0;
int func2=1;
for(int i=2;i<=n;i++) {
int temp=f2;
func2=(func1+func2)%1000000007;
func1=temp;
}
return func2;
}
};