本文正在参加「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);
}
}