第九章 动态规划part01(代码随想录)

如果某一问题有很多重叠子问题,使用动态规划是最有效的。动态规划中每一个状态一定是由上一个状态推导出来的。

注意的点:

1. 确定dp[i][j] dp数组以及下标的含义

2. 确定递推公式

3. dp数组如何初始化

4. 确定遍历顺序(例如为什么先遍历背包再遍历物品

5. 举例推导dp数组(打印dp数组)

 509. 斐波那契数 

1. 确定dp[i][j] dp数组以及下标的含义

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

2. 确定递推公式(如题)

dp[i] = dp[i - 1] + dp[i - 2];

3. dp数组如何初始化(如题)

dp[0]=1; dp[1]=1;

4. 确定遍历顺序

从前向后遍历

5. 打印dp数组

不需要维护一个数组,用个sum就行

当前层只依赖于上2层,维护2层即可,状态压缩。

class Solution {
public:
    int fib(int n) {
        int dp[2];
        // dp数组初始化
        dp[0]=0;
        dp[1]=1;

        // 边界处理
        if (n<=1){
            return n;
        }
        // 遍历顺序
        for (int i=2; i<=n; i++){// 求到第n个
            // 计算新sum
            int sum = dp[0] + dp[1];
            // 更新dp[0],dp[1]
            dp[0] = dp[1];
            dp[1] = sum;
        } 
        return dp[1];
    }
};

 

70. 爬楼梯   

输入:n = 1
输出:1
解释:有一种方法可以爬到楼顶。
1. 1 阶 

输入:n = 2
输出:2
解释:有两种方法可以爬到楼顶。
1. 1 阶 + 1 阶
2. 2 阶
输入:n = 3 (1阶再走一步走2阶到3阶、2阶再走一步走1阶到3阶)
输出:3
解释:有三种方法可以爬到楼顶。
1. 1 阶 + 1 阶 + 1 阶
2. 1 阶 + 2 阶
3. 2 阶 + 1 阶
输入:n = 4 (2阶再走一步走2阶到4阶、3阶再走一步走1阶到4阶)
输出:5
解释:有四种方法可以爬到楼顶。
1. 1 阶 + 1 阶 + 1 阶 + 1 阶
2. 1 阶 + 1 阶 + 2 阶
3. 2 阶 + 1 阶 + 1 阶
4. 1 阶 + 2 阶 + 1 阶
5. 2 阶 + 2 阶

1. 确定dp[i][j] dp数组以及下标的含义

dp[i]的定义为:爬到第i层楼梯,有dp[i]种方法

2. 确定递推公式

dp[i] = dp[i - 1] + dp[i - 2]

3. dp数组如何初始化

n是正整数dp[0]不需初始化。

所以我的原则是:不考虑dp[0]如何初始化,只初始化dp[1] = 1,dp[2] = 2,然后从i = 3开始递推,这样才符合dp[i]的定义。

4. 确定遍历顺序

从前向后,dp[i - 1]、dp[i - 2]才是经过计算的

5. 打印dp数组

70.爬楼梯

class Solution {
public:
    int climbStairs(int n) {
        if (n<=1) return n;
        int dp[3];
        dp[1]=1;
        dp[2]=2;
        for (int i=3; i<=n; i++){
            int sum = dp[1]+dp[2];
            dp[1] = dp[2];
            dp[2] = sum;
        }
        return dp[2];
    }
};

 

 746. 使用最小花费爬楼梯 

 

求到楼顶的最小花费
1. 确定dp[i][j] dp数组以及下标的含义

dp[i]的定义为:到达第i台阶所花费的最少体力为dp[i]。

2. 确定递推公式(如题)

由题可知,可选择向上爬一个或者两个台阶:dp[i - 1],dp[i - 2]

dp[i] = dp[i - 1] + cost[i - 1]  // 加上对应花费才能跳到dp[i]

dp[i] = dp[i - 2] + cost[i - 2]

上面2个都能到达楼顶,取最小

min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2])

3. dp数组如何初始化(如题)

看一下递归公式,dp[i]由dp[i - 1],dp[i - 2]推出,既然初始化所有的dp[i]是不可能的,那么只初始化dp[0]和dp[1]就够了,其他的最终都是dp[0]dp[1]推出。

dp[0] = 0;

dp[1] = 0;

“你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。” 也就是说 到达 第 0 个台阶是不花费的,但从 第0 个台阶 往上跳的话,需要花费 cost[0]

4. 确定遍历顺序

从前向后

5. 打印dp数组

 

class Solution:
    def minCostClimbingStairs(self, cost: List[int]) -> int:
        dp = [0]*(len(cost)+1) # dp数组初始化
        dp[0] = 0
        dp[1] = 0
        for i in range(2, len(cost) + 1):
            # 在第i步,可以选择从前一步(i-1)花费体力到达当前步,或者从前两步(i-2)花费体力到达当前步
            # 选择其中花费体力较小的路径,加上当前步的花费,更新dp数组
            dp[i] = min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2])
        return dp[len(cost)] # 返回到达楼顶的最小花费

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值