首先看一个经典问题:
假设你正在爬楼梯。需要 n 阶你才能到达楼顶,你每次可以爬 1阶或者 2阶,问你有多少种方法爬到楼顶
示例:
输入:2,输出:2
输入:3,输出:3
思路分析:
这道题目只求到达目的地解法个数,不需要求具体的解决路径
递归+记忆化搜索
首先用递归 + 记忆化搜索解决,记忆化搜索主要用来解决递归项的重复计算问题
const cache = [] // 记忆化搜索就是在递归里加缓存,自顶向下const climbStairs = function(n){// 递归先写边界条件if(n===1){return 1}if(n===2){return 2}if(!cache[n]){cache[n] = climbStairs(n-1) + climbStairs(n-2) // 递归式}return cahch[n]}
递归式cache[n] = climbStairs(n-1) + climbStairs(n-2)是自顶向下思考的,从最后的结果倒着往前推。
动态规划
动态规划与递归思路相反,是自底向上的思考,通过状态转移方程进行遍历从底部计算到顶部
这道题的状态转移方程和递归式一样:f(n) = f(n-1) + f(n-2)
const climb = function(n){const cache = []cache[1] = 1cache[2] = 2for(let i=3; i<= n;i++){cache[n] = cache[n-1] + cache[n-2]}return cache[n]}
由上我们可以看出,动态规划问题有两个关键特征:
- 整体的最优解包含着子问题最优解
- 子问题的最优解会被多次计算,需要缓存来提高性能
