动态规划
递归与动态规划导论
509-斐波那契数
斐波那契数列 [0, 1, 1, 2, 3, 5, 8, ...] 可以表示为递归形式:
int fib(n) {
if (n == 0) return 0;
if (n == 1) return 1;
return fib(n-1) + fib(n-2);
}
涉及递归的问题都可以画出递归树,对于分析算法复杂度、寻找算法低效的原因、找到高效的解法有很大帮助!假设求 fib(20),画出递归树后会发现,这个递归存在着大量重复计算,假设 N = 20,那么树的高度是 20,树的节点数是 2 ^ N,算法复杂度是 O(2^n),这太大了!

因此我们可以用一个数组或者哈希表存储已经计算过的结果,当遍历递归树遇到同样的节点时,就可以快速访问到结果而不必重复计算,这就是“剪枝”。通过剪枝,把一颗存在巨量冗余的递归树,变成了不存在冗余的递归图,fib(20) ... fib(1) 每个结 果都只计算了一次。这就是“记忆化递归”!

递归的思路是把一个大问题,自顶向下分解成子问题,最后到达递归树的叶子结点,然后逐层返回计算结果。而动态规划的思想,是从最小子问题开始,即 f(1) 和 f(2),自底向上,逐步构建出大问题的解。
class Solution {
public:
int fib(int n) {
if (n <= 1) return n;
vector<int> dp(n+1, 0);
dp[1] = 1;
for (int i = 2; i <= n; ++i) {
dp[i] = dp[i-1] + dp[i-2];
}
return dp[n];
}
};