给你一个整数数组 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数组的状态变化,如下:
- // leetCode 746.使用最小花费爬楼梯
- class Solution {
- public:
- // 记得扇贝
- int minCostClimbingStairs(vector<int>& cost) {
- vector<int> dp(cost.size()+1,0);
- dp[0] = 0;// 默认第一步都是不花费体力的
- dp[1] = 0;
- for(int i=2;i<=cost.size();i++) {
- dp[i] = min(dp[i-1] + cost[i-1] ,dp[i-2] + cost[i-2]);
- }
- return dp[cost.size()];
- }
- };
进一步优化空间复杂度,因为dp[i]可由前两位推出,也就不用dp数组了
- // leetCode 746.使用最小花费爬楼梯
- class Solution {
- public:
- // 方法1 动态规划 进一步优化
- int minCostClimbingStairs(vector<int>& cost) {
- int dp0 = 0;
- int dp1 = 0;
- for(int i=2;i<=cost.size();i++) {
- int dpi = min(dp1 + cost[i-1],dp0 + cost[i-2]);
- dp0 = dp1;
- dp1 = dpi;
- }
- return dp1;
- }
- };
拓展:旧力扣中的题意是,如果按照 第一步是花费的,最后一步不花费,那么该如何写代码呢?
- class Solution {
- public:
- int minCostClimbingStairs(vector<int>& cost) {
- vector<int> dp(cost.size());
- dp[0] = cost[0]; // 第一步有花费
- dp[1] = cost[1];
- for (int i = 2; i < cost.size(); i++) {
- dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i];
- }
- // 注意最后一步可以理解为不用花费,所以取倒数第一步,第二步的最少值
- return min(dp[cost.size() - 1], dp[cost.size() - 2]);
- }
- };
参考和推荐文章、视频: