代码随想录打卡第41天|理论基础及代码框架|509. 斐波那契数 ● 70. 爬楼梯 ● 746. 使用最小花费爬楼梯

动态规划

概念:动态规划中每一个状态一定是由上一个状态推导出来的

动态规划问题的解题步骤

具体步骤

解动态规划问题可以按照下面的五部曲进行求解

1.确定dp数组(dp table)以及下标的含义

dp数组是存储事物的状态的数组
在确定dp数组时,我们应该明确:
1)确定dp数组的含义时通常要结合题目让我们求什么来定义
2)其次要考虑这么定义dp数组是否可以找到正确的递推关系

2.确定递推公式

动态规划的一个特征是,它的第i个状态是由它之前的状态推导出来的,所以我们要找到决定第i个状态的公式,通常由前几个状态推导得出。

3.dp数组如何初始化

初始化时 是要到边界 后面的状态通过前面状态的推导可以得到 什么时候不能接着往前推了 我们就找到了边界 如果是一维dp数组 边界通常是dp[0]
初始化时 应该结合题意和dp数组的含义 而且一定要保证推导的正确性

4.确定遍历顺序

我们要看递推公式是怎么推的 从而确定递推顺序 要保证你通过前面的状态推导当前状态时,前面的状态是有值的

5.举例推导dp数组(debug)

这个常用于debug

举个栗子

下面以一个具体的题目来举例动规上述五步曲的使用,以方便各位的理解
题目:斐波那契数
力扣链接:509.斐波那契数

1.确定dp数组以及下标的含义

dp[i]的定义为:第i个数的斐波那契数值是dp[i]

2.确定递推公式

这道题目已经把递推公式直接给我们了:状态转移方程 dp[i] = dp[i - 1] + dp[i - 2];

3.dp数组如何初始化

题目中把如何初始化也直接给我们了,如下:
dp[0] = 0; dp[1] = 1;

4.确定遍历顺序

从递归公式dp[i] = dp[i - 1] + dp[i - 2];中可以看出,dp[i]是依赖 dp[i - 1] 和 dp[i - 2],那么遍历的顺序一定是从前到后遍历的

5.举例推导dp数组

按照这个递推公式dp[i] = dp[i - 1] + dp[i - 2],我们来推导一下,当N为10的时候,dp数组应该是如下的数列:

0 1 1 2 3 5 8 13 21 34 55

完整代码如下
class Solution {
public:
    int fib(int N) {
        if (N <= 1) return N;
        //dp数组
        vector dp(N + 1);
        //初始化
        dp[0] = 0;
        dp[1] = 1;
        //遍历
        for (int i = 2; i <= N; i++) {
        //递推
            dp[i] = dp[i - 1] + dp[i - 2];
        }
        return dp[N];
    }
};

70. 爬楼梯

**题目:**假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
题目链接:70.爬楼梯
**解题思路:**动态规划五部曲
1.确定dp数组以及下标的含义
dp[n] 到第n阶有多少方法
2.确定递推公式
dp[n]=dp[n-1]+dp[n-2]
3.dp数组如何初始化
dp[0]=1
4.确定遍历顺序
从前向后遍历
代码如下:

public int climbStairs(int n) {
    int[] dp = new int[n + 1];
    dp[0] = 1;
    dp[1] = 1;
    for (int i = 2; i <= n; i++) {
        dp[i] = dp[i - 1] + dp[i - 2];
    }
    return dp[n];
}

746. 使用最小花费爬楼梯

**题目:**给你一个整数数组 cost ,其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。一旦你支付此费用,即可选择向上爬一个或者两个台阶。
你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。
请你计算并返回达到楼梯顶部的最低花费。
示例 1:
输入:cost = [10,15,20]
输出:15
解释:你将从下标为 1 的台阶开始。

  • 支付 15 ,向上爬两个台阶,到达楼梯顶部。
    总花费为 15 。
    示例 2:
    输入:cost = [1,100,1,1,1,100,1,1,100,1]
    输出:6
    解释:你将从下标为 0 的台阶开始。
  • 支付 1 ,向上爬两个台阶,到达下标为 2 的台阶。
  • 支付 1 ,向上爬两个台阶,到达下标为 4 的台阶。
  • 支付 1 ,向上爬两个台阶,到达下标为 6 的台阶。
  • 支付 1 ,向上爬一个台阶,到达下标为 7 的台阶。
  • 支付 1 ,向上爬两个台阶,到达下标为 9 的台阶。
  • 支付 1 ,向上爬一个台阶,到达楼梯顶部。
    总花费为 6 。
    题目链接: 746. 使用最小花费爬楼梯
    **解题思路:**动态规划五部曲
    1.确定dp数组以及下标的含义
    dp[n] 到第n阶的最低花费
    2.确定递推公式
    dp[n]=min(dp[n-1]+cost[n-1],dp[n-2]+cost[n-2])
    3.dp数组如何初始化(难点)
    可以从0或1开始 所以在第0个或第一个台阶不花费
    dp[0]=0
    dp[1]=0
    4.确定遍历顺序
    从左向右遍历
    代码如下:
class Solution {
    public int minCostClimbingStairs(int[] cost) {
        int len = cost.length;
        int[] dp = new int[len + 1];

        // 从下标为 0 或下标为 1 的台阶开始,因此支付费用为0
        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];
    }
}

你可能感兴趣的:(代码随想录,动态规划,算法)