代码随想录算法训练营第三十八天|509. 斐波那契数、70. 爬楼梯、746. 使用最小花费爬楼梯

108 阅读3分钟

动态规划理论基础

动态规划的题目由重叠子问题构成,每一个状态一定是由上一个状态推导出来的。

动态规划五部曲

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

动态规划里面递推公式十分重要,但是确定dp数组,初始化,遍历顺序也同样十分重要,一定要严格按照这五步进行,将每一步的思路理清。

当做动态规划的题目遇到问题时,最好的方式就是打印出dp数组,看是否和自己推理的一样。

509. 斐波那契数

题目链接:509. 斐波那契数

思路:动态规划五步曲:

  1. dp[i]代表第i个数的斐波那契数是多少。
  2. 递推公式:dp[i] = dp[i - 1] + dp[i - 2]
  3. 初始化dp[0] = 0, dp[1] = 1
  4. 从递推公式可以看出,一定是从前向后遍历的。
  5. 举例看是否可行
class Solution {
    public int fib(int n) { // 动态规划
        if (n == 0) return 0;
        if (n == 1) return 1;
        int dp0 = 0;
        int dp1 = 1;
        for (int i = 2; i <= n; i++) {
            int temp = dp1;
            dp1 += dp0;
            dp0 = temp;
        }
        return dp1;
    }
}

70. 爬楼梯

题目链接:70. 爬楼梯

思路:动态规划五部曲

  1. dp[i]表示爬到第i层可以有几种方式
  2. 递推公式:dp[i] = dp[i - 1] + dp[i - 2](推导过程参考随想录)
  3. 初始化dp[1] = 1, dp[2] = 2
  4. 从递推公式可以看出是从前向后遍历。
  5. 举例看是否可行
class Solution {
    public int climbStairs(int n) {
        if (n == 1) return 1;
        // 1、确定dp数组及下标含义
        // dp[i]代表当前阶有几种方法
        int[] dp = new int[n + 1];
        // 2、确定递推函数
        // dp[i] = dp[i - 1] + (i) - 2
        // 3、确定初始化
        dp[1] = 1;
        dp[2] = 2;
        // 4、确定遍历顺序
        for (int i = 3; i <= n; i++) {
            dp[i] = dp[i - 1] + dp[i - 2];
        }
        return dp[n];
    }
}

本题与斐波那契相同,可以降低空间复杂度。

746. 使用最小花费爬楼梯

题目链接:746. 使用最小花费爬楼梯

思路:动态规划五步曲

  1. dp[i]代表到达第i个台阶所花费的最小体力(这里认为第一步无需支付费用)
  2. 递推公式:dp[i] = Math.min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]),因为到达第i个台阶的途径有两种,从dp[i - 1]或者dp[i - 2],比较从这两个过来哪一个花费更小即可。
  3. 初始化,dp[0] = 0, dp[1] = 0。我们认为第一步无需支付费用,所以到第一个台阶和到第二个台阶都是0。
  4. 遍历顺序为从前到后
  5. 举例是否符合
class Solution {
    public int minCostClimbingStairs(int[] cost) {
        int len = cost.length;
        int[] dp = new int[len + 1];
        // 每次最多走两步,前两个台阶无需支付费用
        dp[0] = 0;
        dp[1] = 0;
        // 计算到达每一层台阶的最小费用
        for (int i = 2; i <= len; i++) {
            dp[i] = Math.min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]);
        }

        return dp[len];
    }
}