动态规划解最小花费爬楼梯问题:LeetCode 746. 使用最小花费爬楼梯
1. 题目链接
题目要求:给定一个整数数组 cost
,其中 cost[i]
是从楼梯第 i
阶向上爬所需支付的费用。你可以从下标 0
或 1
的台阶开始爬,每次爬1或2阶,计算达到楼梯顶部(数组末尾之后)的最小花费。
2. 题目描述
- 输入 :整数数组
cost
,例如[10, 15, 20]
。 - 输出 :最小花费,例如
15
(从下标1开始,直接走两步到达顶部)。 - 约束条件 :
2 ≤ cost.length ≤ 1000
0 ≤ cost[i] ≤ 999
3. 示例分析
示例 1 :
输入:cost = [10, 15, 20]
输出:15
解释:
- 从下标1开始,支付15,走两步直接到达顶部,总花费为15。
示例 2 :
输入:cost = [1, 100, 1, 1, 1, 100, 1, 1, 100, 1]
输出:6
解释:
- 路径为
0→2→4→6→7→9→顶部
,总花费为1+1+1+1+1+1=6
。
4. 算法思路
动态规划递推
-
状态定义:
dp[i]
表示到达第i
阶的最小累计花费。- 注意 :顶部位于第
n
阶(n = cost.size()
),因此需要计算dp[n]
。
-
状态转移方程:
- 到达第
i
阶的最小花费由前两阶的花费决定:
dp[i] = min(dp[i-1] + cost[i-1], dp[i-2] + cost[i-2])
- 解释:可以从第
i-1
阶走1步,或从第i-2
阶走2步到达第i
阶。
- 到达第
-
初始条件:
dp[0] = 0
(从起点开始,无需站在下标0的台阶)。dp[1] = 0
(从起点开始,直接选择下标1的台阶,无需支付下标1的费用)。
5. 边界条件与注意事项
-
边界处理:
- 当
cost
数组长度为1
时,直接返回0
(无需支付任何费用即可到达顶部)。 - 当长度为
2
时,返回min(cost[0], cost[1])
。
- 当
-
时间复杂度 :
O(n)
,只需遍历一次数组。 -
空间优化 :可进一步优化为滚动变量,将空间复杂度从
O(n)
降至O(1)
。
6. 代码实现与解析
cpp
class Solution {
public:
int minCostClimbingStairs(vector<int>& cost) {
int n = cost.size();
if (n == 0) return 0; // 处理空数组(题目约束n≥2,实际无需)
if (n == 1) return 0; // 关键修正:避免越界
vector<int> dp(n + 1, 0); // dp[i]表示到达第i阶的最小花费
for (int i = 2; i <= n; i++) {
dp[i] = min(dp[i-1] + cost[i-1], dp[i-2] + cost[i-2]);
}
return dp[n];
}
};
代码解析
- 初始化处理 :
- 直接处理
n=0
和n=1
的情况,避免越界错误。
- 直接处理
- 动态规划数组 :
dp[0]
和dp[1]
初始化为0
,因为从起点可以选择直接站在下标0或1的位置。
- 递推计算 :
- 从
i=2
开始,计算到达每阶的最小花费,确保每次取最小值。
- 从
- 返回值 :
dp[n]
表示到达顶部(第n
阶之后)的最小花费。
总结
通过动态规划递推能够高效解决最小花费爬楼梯问题。关键点在于正确处理边界条件(如 n=1
)和状态转移逻辑。此方法可扩展至类似路径选择问题,如带权重的跳跃游戏等。