第九章动态规划——使用最小花费爬楼梯

目录

力扣题号:746. 使用最小花费爬楼梯 - 力扣(LeetCode)

题目描述

示例

提示

思路

解法一:动态规划第一种递推公式

(1)确定dp数组及其下标的含义

(2)确定递归公式

(3)初始化dp数组

(4)确定遍历的顺序

(5)根据逻辑推出dp数组的值

代码实现

解法二:动态规划第二种递推公式

(1)确定dp数组及其下标的含义

(2)确定递归公式

(3)初始化dp数组

(4)确定遍历的顺序

(5)根据逻辑推出dp数组的值

代码实现

总结


力扣题号:746. 使用最小花费爬楼梯 - 力扣(LeetCode)

注:下述题目描述和示例均来自力扣

题目描述

        给你一个整数数组 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 。

提示

  • 2 <= cost.length <= 1000
  • 0 <= cost[i] <= 999


思路

解法一:动态规划第一种递推公式

        就目前看来,这道题应该就是另一道题爬楼梯的升级版本,更难了一点,对动态规划的理解需要更加的深一点,这样便可以简单的得到这道题的答案。

        再写动态规划五部曲之前,我们先看一下示例,很容易会发现,他对于最后一步是不计算花费的,这一点还是挺重要的。

        如果直接进入动态规划五部曲的话,那么推理的思路如下所示:

(1)确定dp数组及其下标的含义

        我们这里的dp[1]代表走到当前位置的最小花费。

(2)确定递归公式

        我们来想想,它从第一位或第二位开始,然后每次跳一位或者两位。很多同学在第一次看到这个题目的时候,发现可以从第一位开始或者从第二位开始,这好像增加的难度,但是如果你仔细的理解一下,会发现其实这照应起来了对吧。然后我们直接判断每一个节点到达这个节点的最小花费即可,所以可以得到下面的递推公式:

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

        这是当前位置需要的花费和前两个位置中的最小花费加上得到到当前位置的最小花费。

        当我们处理完全部位置之后就可以将目光注视在这最后两个位置的数据上了,为什么?因为我们可以一步走两个位置或者一个位置,并且最后一步是没有花费的,所以只需要看前两个位置谁花费最小然后就可以得出答案了。

(3)初始化dp数组

        这里的初始化你可以看作由前面的格子跳了一步或者两步完成记录这两个格子的花费的任务。所以初始化如下:

dp[0] = cost[0] , dp[1] = cost[1]

(4)确定遍历的顺序

        这里的遍历顺序显然也是从前往后的顺序,没有一点毛病。

(5)根据逻辑推出dp数组的值

        根据逻辑推出来的dp数组的值如下:

        [1, 100, 2, 3, 3, 103, 4, 5, 104, 6]

代码实现

class Solution {
    public static int minCostClimbingStairs(int[] cost) {
        int len = cost.length;
        if(cost.length < 3){
            // 如果只有两个直接返回小的那个
            return Math.min(cost[0], cost[1]);
        }

        // 定义dp数组
        int[] dp = new int[len];
        
        // 初始化dp数组
        dp[0] = cost[0];
        dp[1] = cost[1];
        // 进入遍历顺序
        for(int i = 2 ; i < len; i++){
            // 递推公式
            dp[i] =  cost[i] + Math.min(dp[i - 1], dp[i - 2]);
        }
        // 返回最后两个值中的最小值
        return Math.min(dp[len - 1], dp[len - 2]);
    }
}


解法二:动态规划第二种递推公式

       这道题我是直接使用第一种递推公式就解决了,然后我想看一下力扣的题解看有没有其他思路,果然它的递推公式和我的思路不一样,但是核心思想还是差不多。

       再来一次直接进入动态规划五部曲的话,那么推理的思路如下所示:

(1)确定dp数组及其下标的含义

        我们这里的dp[1]代表走到当前位置的最小花费。这个并没有变化对吧emmmmmm,其实这两个不同是思路的差别在于,我加没加当前所处位置所需要的花费,这第二种思路没加,我第一种思路加了。

(2)确定递归公式

        我们一直寻找的是之前一个位置,或者两个位置的最小花费加上他俩自身的花费来到达当前 i

 的位置的花费,最后的位置的数据就是我们的答案,所以可以得到下面的递推公式:

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

        这是到达当前位置所需要的花费,并不包括当前位置的花费

(3)初始化dp数组

        这里的初始化就是完全没有花费了,因为根据我们这里的思路来说,这里是起点,所以没有一点花费。所以初始化如下:

dp[0] = 0 , dp[1] = 0

(4)确定遍历的顺序

        这里的遍历顺序显然也是从前往后的顺序,没有一点毛病。

(5)根据逻辑推出dp数组的值

        根据逻辑推出来的dp数组的值如下:

        [0, 0, 1, 2, 2, 3, 3, 4, 4, 5, 6]

        细心的兄弟可能发现了比我上一个dp数组多了一位,为什么?因为这里是多了最后一步来记录,而真实情况中(也就是在cost中的最后一步就不需要处理了,当然也就没有被记录上)这一步是不被记录了,因为已经结束了。

代码实现

class Solution {
    public static int minCostClimbingStairs(int[] cost) {
        int len = cost.length;
        if(cost.length < 3){
            // 如果只有两个直接返回小的那个
            return Math.min(cost[0], cost[1]);
        }

        // 定义dp数组
        int[] dp = new int[len];
        
        // 初始化dp数组
        dp[0] = cost[0];
        dp[1] = cost[1];
        // 进入遍历顺序
        for(int i = 2 ; i < len; i++){
            // 递推公式
            dp[i] =  cost[i] + Math.min(dp[i - 1], dp[i - 2]);
        }
        // 返回最后两个值中的最小值
        return Math.min(dp[len - 1], dp[len - 2]);
    }
}


总结

        动态规划就玩吧,其实初始化搞定,dp数组搞定,递推公式搞定也就搞定啦。^_^

  • 26
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WenJGo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值