问题分析
这是一个典型的动态规划问题,目标是找到爬上楼梯的最低体力消耗。可以从第 0 或第 1 个阶梯开始,每次可以选择爬 1 或 2 个阶梯,最终需要到达数组末尾之后的位置(即楼顶)。
动态规划解法
动态规划的核心是定义状态和状态转移方程。设 dp[i]
表示到达第 i
个阶梯时的最低体力消耗。
状态转移方程
对于第 i
个阶梯,可以从 i-1
或 i-2
阶梯到达:
- 如果从
i-1
到达,则消耗为dp[i-1] + cost[i-1]
; - 如果从
i-2
到达,则消耗为dp[i-2] + cost[i-2]
。
因此,状态转移方程为: [ dp[i] = \min(dp[i-1] + cost[i-1], dp[i-2] + cost[i-2]) ]
初始条件
dp[0] = 0
:初始位置可以是第 0 个阶梯,且不需要消耗体力;dp[1] = 0
:初始位置也可以是第 1 个阶梯,同样不需要消耗体力。
目标
最终目标是计算 dp[n]
,其中 n
是数组 cost
的长度。因为楼顶是第 n
个阶梯之后的位置。
代码实现
def minCostClimbingStairs(cost):
n = len(cost)
dp = [0] * (n + 1)
for i in range(2, n + 1):
dp[i] = min(dp[i-1] + cost[i-1], dp[i-2] + cost[i-2])
return dp[n]
示例测试
cost = [10, 15, 20]
print(minCostClimbingStairs(cost)) # 输出:15
解释:
- 从第 1 个阶梯开始(消耗 0),支付 15 后爬 2 步到达楼顶,总消耗为 15。
空间优化
由于 dp[i]
只依赖于 dp[i-1]
和 dp[i-2]
,可以用两个变量代替数组,将空间复杂度优化到 O(1)。
优化后的代码
def minCostClimbingStairs(cost):
prev1, prev2 = 0, 0
for i in range(2, len(cost) + 1):
current = min(prev1 + cost[i-1], prev2 + cost[i-2])
prev2, prev1 = prev1, current
return prev1
复杂度分析
- 时间复杂度:O(n),需要遍历数组一次;
- 空间复杂度:O(1),仅使用常数空间。
边界情况
- 如果
cost
为空,直接返回 0; - 如果
cost
长度为 1,可以从第 0 或第 1 个阶梯开始,直接到达楼顶,因此返回 0。
完整代码示例
def minCostClimbingStairs(cost):
if not cost:
return 0
prev1, prev2 = 0, 0
for i in range(2, len(cost) + 1):
current = min(prev1 + cost[i-1], prev2 + cost[i-2])
prev2, prev1 = prev1, current
return prev1
# 测试
print(minCostClimbingStairs([10, 15, 20])) # 15
print(minCostClimbingStairs([1, 100, 1, 1, 1, 100, 1, 1, 100, 1])) # 6