动态规划二:使用最小花费爬楼梯 | Java刷题打卡

241 阅读2分钟

本文正在参加「Java主题月 - Java 刷题打卡」,详情查看 活动链接

一、题目:746.使用最小花费爬楼梯

数组的每个下标作为一个阶梯,第 i 个阶梯对应着一个非负数的体力花费值 cost[i](下标从 0 开始)。每当你爬上一个阶梯你都要花费对应的体力值,一旦支付了相应的体力值,你就可以选择向上爬一个阶梯或者爬两个阶梯。请你找出达到楼层顶部的最低花费。在开始时,你可以选择从下标为 0 或 1 的元素作为初始阶梯。(注:最后达到顶层不用花费体力值)。例:

  • 输入:cost = [10, 15, 20]
  • 输出:15
  • 解释:最低花费是从 cost[1] 开始,然后走两步即可到阶梯顶,一共花费 15 。

二、解析

每次花费相应的体力值可以选择向上爬一个阶梯或两个阶梯,每次向上爬楼梯的总花费都要由前一个状态决定。后一个状态值需由前一个状态值决定,所以应使用动态规划,而不能使用贪心算法。

动态规划(dp)有三要素:最优子结构、状态转移方程、边界,而找到这三要素是解题关键。可通过以下步骤快速找到动态规划的三要素。

  • 确定dp数组及下标含义
  • 确定递推公式,明确状态转移方程
  • dp数组初始化,明确边界
  • 确定遍历顺序
  • 推到dp数组

确定dp数组及下标含义

本题中,对于dp数组的定义为:第i个台阶所花费的最少体力为dp[i]。

确定递推公式

本题中,爬上第i个阶梯,可通过第i-1个阶梯向上爬一个阶梯到达,也可以通过第i-2个阶梯向上爬两个阶梯到达,要求最小的花费,则有 dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i]

dp数组初始化

在开始时,你可以选择从下标为 0 或 1 的元素作为初始阶梯。即可得,第1、2个阶梯应作为dp数组的初始条件,也就是边界。也符合我们的认知,当还没开始爬楼梯的时候,我们花费的体力应该为0。

明确遍历顺序

本题中很简单,从最底下开始遍历花费的计算比较少的。如果从N往0遍历,就成了一个递归写法,会产生重复的计算。

推到dp数组

根据递推公式,手算或打印出dp数组,验证递推公式的准确性。

三、题解代码

class Solution {
    public int minCostClimbingStairs(int[] cost) {
        int dp1 = cost[0];
        int dp2 = cost[1];

        for(int i = 2;i<cost.length;i++){
            int dpi = Math.min(dp1,dp2) + cost[i];
            dp1 = dp2;
            dp2 = dpi;
        }
        return Math.min(dp1,dp2);
    }
}