动态规划—#746. 使用最小花费爬楼梯
- 前言
- 题目描述
- 基本思路
- 1. 问题定义:
- 2. 理解问题和递推关系:
- 3. 解决方法:
- 4. 进一步优化:
- 5. 小总结:
- 代码实现
- Python3代码实现
- Python 代码解释
- C++代码实现
- C++ 代码解释
- 总结:
前言
在这个问题中,我们有一个数组 c o s t [ ] cost[] cost[],其中 c o s t [ i ] cost[i] cost[i] 表示从第 i i i 个台阶爬到下一个台阶的费用。你可以从第 0 0 0 个台阶或第 1 1 1 个台阶开始,然后每次可以选择爬 1 1 1 个台阶或 2 2 2 个台阶。题目要求的是:你到达楼顶时花费的最小费用是多少?
你需要计算的是,在爬到楼顶时,花费的最小费用。楼顶位于 c o s t cost cost 数组的末尾之后的一个位置,即爬完最后一个台阶后,你就到达了楼顶。
题目描述
基本思路
1. 问题定义:
在这个问题中,我们有一个数组 c o s t [ ] cost[] cost[],其中 c o s t [ i ] cost[i] cost[i] 表示从第 i i i 个台阶爬到下一个台阶的费用。你可以从第 0 0 0 个台阶或第 1 1 1 个台阶开始,然后每次可以选择爬 1 1 1 个台阶或 2 2 2 个台阶。题目要求的是:你到达楼顶时花费的最小费用是多少?
你需要计算的是,在爬到楼顶时,花费的最小费用。楼顶位于 c o s t cost cost 数组的末尾之后的一个位置,即爬完最后一个台阶后,你就到达了楼顶。
2. 理解问题和递推关系:
到达楼顶的最小费用可以通过递推计算:
- 假设 d p [ i ] d p[i] dp[i] 是爬到第 i i i 个台阶的最小花费。
- 你可以从 i − 1 i-1 i−1 或者 i − 2 i-2 i−2 台阶爬到第 i i i 个台阶。相应地,爬到第 i i i 台阶的最小花费是前面两阶的最小花费,加上 cost [ i ] \operatorname{cost}[i] cost[i] :
d p [ i ] = min ( d p [ i − 1 ] , d p [ i − 2 ] ) + cost [ i ] d p[i]=\min (d p[i-1], d p[i-2])+\operatorname{cost}[i] dp[i]=min(dp[i−1],dp[i−2])+cost[i]
到达楼顶的情况是你从第 n − 1 n-1 n−1 或 n − 2 n-2 n−2 台阶爬上去,而楼顶没有对应的花费。
3. 解决方法:
- 初始条件: 你可以从第 θ \theta θ 或第 1 个台阶开始。因此 d p [ θ ] = cost [ θ ] , d p [ 1 ] = cost [ 1 ] d p[\theta]=\operatorname{cost}[\theta], d p[1]=\operatorname{cost}[1] dp[θ]=cost[θ],dp[1]=cost[1] 。
- 递推公式:对于第 i i i 个台阶, d p [ i ] = min ( d p [ i − 1 ] , d p [ i − 2 ] ) + cost [ i ] d p[i]=\min (d p[i-1], d p[i-2])+\operatorname{cost}[i] dp[i]=min(dp[i−1],dp[i−2])+cost[i] 。
- 目标: 计算出 d p [ n − 1 ] d p[n-1] dp[n−1] 或 d p [ n − 2 ] d p[n-2] dp[n−2] 的最小值,因为到达楼顶时你可能是从这两个台阶之一爬上去的。
4. 进一步优化:
我们注意到在每一步递推时, d p [ i ] d p[i] dp[i] 只依赖于 d p [ i − 1 ] d p[i-1] dp[i−1] 和 d p [ i − 2 ] d p[i-2] dp[i−2] ,因此可以用两个变量代替整个 dp[] 数组,减少空间复杂度。
- 时间复杂度: O ( n ) O(n) O(n) ,因为我们只需要遍历一次数组。
- 空间复杂度: O ( 1 ) O(1) O(1) ,只需要常量空间保存前两阶的最小费用。
5. 小总结:
- 本质是一个动态规划问题,通过递推公式 d p [ i ] = min ( d p [ i − 1 ] , d p [ i − 2 ] ) + cost [ i ] d p[i]=\min (d p[i-1], d p[i-2])+\operatorname{cost}[i] dp[i]=min(dp[i−1],dp[i−2])+cost[i] 来逐步计算。
- 我们可以通过优化将空间复杂度从 O ( n ) O(n) O(n) 降低到 O ( 1 ) O(1) O(1) 。
- 目标是计算出到达楼顶的最小花费,最后从 n − 1 n-1 n−1 或 n − 2 n-2 n−2 台阶上去。
以上就是使用最小花费爬楼梯问题的基本思路。
代码实现
Python3代码实现
class Solution:
def minCostClimbingStairs(self, cost: list[int]) -> int:
# 如果台阶数少于 2 直接返回最低的花费
if len(cost) == 0:
return 0
elif len(cost) == 1:
return cost[0]
# 初始化前两个台阶的最小花费
prev2 = cost[0]
prev1 = cost[1]
# 从第3个台阶开始(即索引2),逐步计算每个台阶的最小花费
for i in range(2, len(cost)):
current = min(prev1, prev2) + cost[i]
prev2 = prev1 # 更新前一个台阶的花费
prev1 = current # 更新当前台阶的花费
# 到达楼顶的最小花费可以从倒数第一或倒数第二个台阶上去
return min(prev1, prev2)
Python 代码解释
- Base Case: 如果 c o s t [ ] cost[] cost[] 长度为 0 或 1 ,直接返回最小花费。
- 动态规划:用 prev2 和 prev1 存储爬到前两个台阶的最小花費,并依次更新。
- 最终结果:返回最后两个台阶中较小的花费。
C++代码实现
class Solution {
public:
int minCostClimbingStairs(vector<int>& cost) {
// 如果台阶数少于2,直接返回最低的花费
if (cost.size() == 0) return 0;
if (cost.size() == 1) return cost[0];
// 初始化前两个台阶的最小花费
int prev2 = cost[0];
int prev1 = cost[1];
// 从第3个台阶开始(即索引2),逐步计算每个台阶的最小花费
for (int i = 2; i < cost.size(); ++i) {
int current = min(prev1, prev2) + cost[i];
prev2 = prev1; // 更新前一个台阶的花费
prev1 = current; // 更新当前台阶的花费
}
// 到达楼顶的最小花费可以从倒数第一或倒数第二个台阶上去
return min(prev1, prev2);
}
};
C++ 代码解释
- Base Case: 如果 c o s t [ ] cost[] cost[] 长度为 0 或 1 ,直接返回最小花费。
- 动态规划:用两个变量 prev2 和 prev1 来存储前两个台阶的最小花费,通过循环不断更新。
- 最终结果:返回最后两个台阶的最小花费。
总结:
- 该问题的核心是动态规划,通过递推公式计算每个台阶的最小花费。
- 为了优化空间复杂度,我们只使用两个变量来存储前两阶的最小花费。
- 通过 Python 和 C++ 的实现,可以有效计算出爬到楼顶的最小费用。