• leetCode 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 。

    力扣的题意可以这样理解,题目中的“你可以选择从下标为0 或 下标为1的台阶开始爬楼梯” 也就是相当于 “跳到 下标0 或者 下标1是不花费体力的,从下标0 下标1开始跳就要花费体力了”

    动规五部曲:

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

    使用动态规则,就要有一个数组来记录状态,本题中只需一个一维数组dp[i]就可以

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

    2.确定递推公式

    可以有两个途径得到dp[i],一个是dp[i-1],一个是dp[i-2]

    dp[i-1] 跳到 dp[i] 需要花费 dp[i-1] + cost[i-1]

    dp[i-2] 跳到 dp[i] 需要花费 dp[i-2] + cost[i-2]

    选择最小的,dp[i] = min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2]);

    3.dp数组初始化

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

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

    4.确定遍历顺序

    从前向后遍历cost数组就可以了

    5.举例推导dp数组

    cost = [1,100,1,1,1,100,1,1,100,1],来模拟一下dp数组的状态变化,如下:

    1. // leetCode 746.使用最小花费爬楼梯
    2. class Solution {
    3. public:
    4. // 记得扇贝
    5. int minCostClimbingStairs(vector<int>& cost) {
    6. vector<int> dp(cost.size()+1,0);
    7. dp[0] = 0;// 默认第一步都是不花费体力的
    8. dp[1] = 0;
    9. for(int i=2;i<=cost.size();i++) {
    10. dp[i] = min(dp[i-1] + cost[i-1] ,dp[i-2] + cost[i-2]);
    11. }
    12. return dp[cost.size()];
    13. }
    14. };
    • 时间复杂度:O(n)
    • 空间复杂度:O(n)

    进一步优化空间复杂度,因为dp[i]可由前两位推出,也就不用dp数组了

    1. // leetCode 746.使用最小花费爬楼梯
    2. class Solution {
    3. public:
    4. // 方法1 动态规划 进一步优化
    5. int minCostClimbingStairs(vector<int>& cost) {
    6. int dp0 = 0;
    7. int dp1 = 0;
    8. for(int i=2;i<=cost.size();i++) {
    9. int dpi = min(dp1 + cost[i-1],dp0 + cost[i-2]);
    10. dp0 = dp1;
    11. dp1 = dpi;
    12. }
    13. return dp1;
    14. }
    15. };
    • 时间复杂度:O(n)
    • 空间复杂度:O(1)

    拓展:旧力扣中的题意是,如果按照 第一步是花费的,最后一步不花费,那么该如何写代码呢?

    1. class Solution {
    2. public:
    3. int minCostClimbingStairs(vector<int>& cost) {
    4. vector<int> dp(cost.size());
    5. dp[0] = cost[0]; // 第一步有花费
    6. dp[1] = cost[1];
    7. for (int i = 2; i < cost.size(); i++) {
    8. dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i];
    9. }
    10. // 注意最后一步可以理解为不用花费,所以取倒数第一步,第二步的最少值
    11. return min(dp[cost.size() - 1], dp[cost.size() - 2]);
    12. }
    13. };

    参考和推荐文章、视频:

    代码随想录 (programmercarl.com)

    动态规划开更了!| LeetCode:746. 使用最小花费爬楼梯_哔哩哔哩_bilibili

  • 相关阅读:
    【【萌新的riscV的学习之关于risc指令集的学习使用总五】】
    python实现图片与视频转换:将视频保存为图片,将批量图片保存为视频
    广度优先搜索算法
    带你吃透MySQL系列:InnoDB引擎浅析
    项目分析(从技术到项目、产品)
    Kotlin文件遍历FileTreeWalk filter
    【HarmonyOS】鸿蒙轻量级智能穿戴应用可以集成华为分析SDK吗?
    Python网络爬虫库:轻松提取网页数据的利器
    前端精度问题 (id 返回的和传给后端的不一致问题)
    微信小程序 在bindscroll事件中监听scroll-view滚动到底
  • 原文地址:https://blog.csdn.net/weixin_41987016/article/details/133325840