思路:
题目的主要信息:
- 斐波那契数列每项的公式为:,从0开始,,
- 求出斐波那契数列的第n项
- n最大不超过39,结果不会超出int的范围,不用考虑
long long
方法一:递归
具体做法:
根据公式,每次返回,结束递归的点就是1或者0
class Solution { public: int Fibonacci(int n) { if (n <= 1) //从0开始,第0项是0,第一项是1 return n; else return Fibonacci(n - 1) + Fibonacci(n - 2); //根据公式递归调用函数 return 0; } };
复杂度分析:
- 时间复杂度:,每个递归会调用两个递归,因此呈现2的指数增长
- 空间复杂度:, 递归栈的最大深度
方法二:递归优化(记忆化递归)
具体做法:
在递归法的基础上,新建一个长度为 n 的数组,用于在递归时存储f(0)至f(n)的数字值,重复遇到某数字则直接从数组取用,避免了重复的递归计算。
class Solution { public: int dp[40] = {0}; //记忆每次已有的结果 int Fibonacci(int n) { if (n <= 1){//从0开始,第0项是0,第一项是1 dp[n] = n; return n; } else{ int a, b; //若是数组中记录了值,直接用省去递归 if(dp[n - 1] == 0) a = Fibonacci(n - 1); else a = dp[n - 1]; if(dp[n - 2] == 0) b = Fibonacci(n - 2); else b = dp[n - 2]; return a + b; } return 0; } };
复杂度分析:
- 时间复杂度:,每个数只有一次计算,没有多余的运算
- 空间复杂度:,使用了辅助数组dp
方法三:动态规划
具体做法:
创建一个n+1大小的辅助数组dp,初始化第0位为0,第1位为1,然后根据公式依次往后相加即可得到后面的值,数组最后的下标n即为所求。
class Solution { public: int Fibonacci(int n) { if (n <= 1) return n; vector<int> dp(n + 1); dp[0] = 0; //从0开始,第0项是0,第一项是1 dp[1] = 1; for (int i = 2; i <= n; i++) dp[i] = dp[i - 1] + dp[i - 2]; //公式相加 return dp[n]; } };
复杂度分析:
- 时间复杂度:,一次遍历
- 空间复杂度:,创建了一个大小为n+1的辅助数组
方法四:动态规划空间优化
具体做法:
动态规划申请了一个数组,但是我们可以发现其实每次需要的只是i-1和i-2的值,我们可以用两个变量保存该值,每次更新即可。
class Solution { public: int Fibonacci(int n) { if (n <= 1) //从0开始,第0项是0,第一项是1 return n; int i_2 = 0; //分别记录i-1与i-2的值 int i_1 = 1; int res = 0; for (int i = 2; i <= n; i++){ res = i_1 + i_2; i_2 = i_1; //更新i-1与i-2 i_1 = res; } return res; } };
复杂度分析:
- 时间复杂度:,其中n为输入的数,一次遍历
- 空间复杂度:,未申请空间