算法练习day33

85 阅读2分钟

一、动态规划理论基础

动态规划,dynamic programming,dp,解决重叠子问题

和贪心的区别在于,动态规划的每个状态是由上一个状态推导出来的,贪心则没有状态推导,而是直接从局部直接选择最优的

动态规划五部曲

  1. 确定dp数组以及下标的含义
  2. 确定递推公式
  3. dp数组如何初始化,(递推公式决定了如何初始化)
  4. 确定遍历顺序
  5. 举例推导dp数组

二、斐波那契数

数列0和1开始,后面每一项是前两项的和

五部曲

  1. dp[i]表示第i个斐波那契数
  2. 递推公式:状态转义方程dp[i] = dp[i-1] + dp[i-2]
  3. 初始化:dp[0] = 0;dp[1] = 1
  4. 遍历顺序: 从前往后
  5. 举例推导dp数组
/**
 * @param {number} n
 * @return {number}
 */
var fib = function(n) {
    let dp = []
    dp[0] = 0
    dp[1] = 1
    for(let i = 2; i <= n;i++) {
        dp[i] = dp[i-1] + dp[i-2]
    }
    return dp[n]
};

简化法

var fib = function(n) {
    if(n < 2) {
        return n
    }
    let res
    let pre = 0
    let cur = 1
    for(let i = 2; i <=n ;i++) {
        res = pre + cur
        pre = cur
        cur = res
    }
    return res
};

递归法

var fib = function(n) {
    function dfs(n) {
        if(n < 2) {
            return n
        }
        return dfs(n-1) + dfs(n-2)
    }
    return dfs(n)
};

三、爬楼梯

  1. dp[i]表示第i层楼的方式
  2. 递推公式:状态转义方程dp[i] = dp[i-1] + dp[i-2]
  3. 初始化:dp[1] = 1;dp[2] = 2
  4. 遍历顺序: 从前往后
  5. 举例推导dp数组
/**
 * @param {number} n
 * @return {number}
 */
var climbStairs = function(n) {
    let dp = []
    dp[1] = 1
    dp[2] = 2
    for(let i = 3; i <= n;i++) {
        dp[i] = dp[i-1] + dp[i-2]
    }
    return dp[n]
};

四、使用最小花费爬楼梯

  1. dp[i]表示第i台阶花费的最少体力
  2. 递推公式:状态转义方程dp[i] = Math.min(dp[i-1] + cost[i-1], dp[i-2] + cost[i-2])
  3. 初始化:dp[0] = 0;dp[1] = 0
  4. 遍历顺序: 从前往后
  5. 举例推导dp数组
/**
 * @param {number[]} cost
 * @return {number}
 */
var minCostClimbingStairs = function(cost) {
    let dp = []
    dp[0] = 0
    dp[1] = 0
    let len = cost.length
    for(let i = 2;i <= len;i++) {
        dp[i] = Math.min(dp[i-1] + cost[i-1], dp[i-2]+cost[i-2])
    }
    return dp[len]
};