持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第5天,点击查看活动详情
题目说明
数组的每个下标作为一个阶梯,第 i 个阶梯对应着一个非负数的体力花费值 cost[i](下标从 0 开始)。
每当爬上一个阶梯都要花费对应的体力值,一旦支付了相应的体力值,就可以选择向上爬一个阶梯或者爬两个阶梯。
请找出达到楼层顶部的最低花费。在开始时,你可以选择从下标为 0 或 1 的元素作为初始阶梯。
示例 1:
输入:cost = [10, 15, 20] 输出:15 解释:最低花费是从 cost[1] 开始,然后走两步即可到阶梯顶,一共花费 15 。
示例 2:
输入:cost = [1, 100, 1, 1, 1, 100, 1, 1, 100, 1] 输出:6 解释:最低花费方式是从 cost[0] 开始,逐个经过那些 1 ,跳过 cost[3] ,一共花费 6 。
动态规划
思路:其实算是一个比较简单的动态规划题了,
- 从第2阶梯:跨1步:`dp[3]=dp[2]+cost[2];`
- 从第1阶梯:跨2步:`dp[3]=dp[1]+cost[1];`
- 怎么选:当然是选花费小的。 f(n) = min (f(n-1)+cost[n-1],f(n-2)+cosr[n-2] )。所以动态规划转移方程就可以推导出来:`dp[3]=Math.min(dp[2]+cost[2],dp[1]+cost[1]);`
- 依此类推:`dp[i]=Math.min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2]);`
动态规划的核心:需要对大量的结果进行比较以选择最优解,如果单纯的使用递归,会导致大量的重复计算,这时候使用动态规划可以有效地避免多余的计算。
class Solution {
public int minCostClimbingStairs(int[] cost) {
int[] dp = new int[cost.length+1];//dp[j]代表前j个台阶用的最小的体力
dp[0] = cost[0];
dp[1] = cost[1];
for(int i =2;i<cost.length;i++){
dp[i] = Math.min(dp[i-1],dp[i-2])+cost[i];
}
return (int)Math.min(dp[cost.length-1],dp[cost.length-2]);
}
}
注意点
这里的解释我感觉有点歧义:走两步即可到阶梯顶这个说法有误, 应该是从 cost[1] = 15 这层出发,走一步就到达了 cost[2] = 20 的位置。可能会认为是 这样总花费不就是 15 + 20 = 30 了吗? 其实不是,20 代表离开这个台阶需要的花费,到达这个台阶后不再移动,是不需要花费这个 20 的。
我认为解释为:
最低花费是从 cost[1] 开始,然后走一步即可到达最后一个台阶,一共花费 15,更合适。