1、问题描述
给你一个整数数组 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
2、解题思路
1. 定义 DP 数组
-
dp[i]表示 爬到第i阶楼梯的最小花费。 -
由于可以选择从
0或1开始,初始化:-
dp[0] = cost[0](从第0阶开始的花费) -
dp[1] = cost[1](从第1阶开始的花费)
-
2. 状态转移方程
-
对于
i >= 2,爬到第i阶的最小花费 = 当前阶的花费cost[i]+ 从i-1或i-2爬上来的最小花费:
dp[i] = cost[i] + Math.min(dp[i-1], dp[i-2]);
3. 最终结果
-
由于最后一步可以直接从
n-1或n-2跨到顶部,所以最终结果是:
return Math.min(dp[cost.length - 2], dp[cost.length - 1]);
public int minCostClimbingStairs(int[] cost) {
int[] dp = new int[cost.length+1];
dp[0] = cost[0];//1
dp[1] = cost[1];//100
for (int i = 2; i < cost.length; i++) {
dp[i] = cost[i] + Math.min(dp[i-1], dp[i-2]); //爬到第 i 阶的最小花费 = 当前阶的花费 cost[i] + 从 i-1 或 i-2 爬上来的最小花费
}
return Math.min(dp[cost.length - 2], dp[cost.length - 1]);//由于最后一步可以直接从 n-1 或 n-2 跨到顶部,所以最终结果是返回两者之间最小值
}
优化空间:不使用数组的 DP 实现
上面的代码使用了 O(n) 空间存储 dp 数组,但我们可以优化成 O(1) 空间,因为 dp[i] 只依赖 dp[i-1] 和 dp[i-2]。
优化思路
-
用 3 个变量 代替
dp数组:-
prev1表示dp[i-2](前两阶的最小花费) -
prev2表示dp[i-1](前一阶的最小花费) -
current表示dp[i](当前阶的最小花费)
-
public int minCostClimbingStairs(int[] cost) {
int n = cost.length;
int prev1 = cost[0]; // dp[0]
int prev2 = cost[1]; // dp[1]
for (int i = 2; i < n; i++) {
int current = cost[i] + Math.min(prev1, prev2);
prev1 = prev2; // 更新 prev1 为前一阶的值
prev2 = current; // 更新 prev2 为当前阶的值
}
return Math.min(prev1, prev2); // 最后一步可以从 n-2 或 n-1 跨到顶部
}
复杂度分析
-
时间复杂度:
O(n),遍历一次cost数组。 -
空间复杂度:
O(1),仅用 3 个变量存储状态。
504

被折叠的 条评论
为什么被折叠?



