编程问题:
斐波那契数,通常用 F(n) 表示,形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是
F(0) = 0,F(1) = 1
F(n) = F(n - 1) + F(n - 2),其中 n > 1
给定 n ,请计算 F(n) 。
示例:
- 输入:2
输出:1
解释:F(2) = F(1) + F(0) = 1 + 0 = 1 - 输入:3
输出:2
解释:F(3) = F(2) + F(1) = 1 + 1 = 2 - 输入:4
输出:3
解释:F(4) = F(3) + F(2) = 2 + 1 = 3
解法:
1.暴力递归
时间复杂度O(2^N)
空间复杂度O(1)
class Solution {
public:
int fib(int n) {
if (n == 0 || n == 1)
return n;
return fib(n - 1) + fib(n -2);
}
};
2.带备忘录的递归解法(自顶向下)
时间复杂度O(N)
空间复杂度O(N)
class Solution {
private:
int helper(vector<int>& memo, int n) {
// base case
if (n == 0 || n == 1) return n;
// 已经计算过 直接查表
if (memo[n] != 0) return memo[n];
memo[n] = helper(memo, n - 1) + helper(memo, n - 2);
return memo[n];
}
public:
int fib(int n) {
// 备忘录全初始化为 0
vector<int> memo(n + 1, 0);
// 进行带备忘录的递归
return helper(memo, n);
}
};
3.dp 数组的迭代解法(自底向上)
时间复杂度O(N)
空间复杂度O(N)
class Solution {
public:
int fib(int n) {
if (n == 0 || n == 1) return n;
vector<int> dp(n + 1, 0);
// base case
dp[0] = 0;
dp[1] = 1;
for (int i = 2; i <= n; i++)
dp[i] = dp[i - 1] + dp[i - 2];
return dp[n];
}
};
状态压缩版(如果我们发现每次状态转移只需要 DP table 中的一部分,那么可以尝试用状态压缩来缩小 DP table 的大小,此问题就相当于把DP table 的大小从 n 缩小到 2)
时间复杂度O(N)
空间复杂度O(1)
class Solution {
public:
int fib(int n) {
if (n == 0 || n == 1)
return n;
int prev = 0, curr = 1;
for (int i = 2; i <= n; i++) {
int sum = prev + curr;
prev = curr;
curr = sum;
}
return curr;
}
};