使用最小花费爬楼梯 图解题解
这道题到底在问什么
- 输入
- cost=[1,100,1,1,1,100,1,1,100,1]
- 输出
- 6
最优解:为什么这么做
一句话答案:LeetCode 746 使用最小花费爬楼梯用一维 DP:dp[i] 记到 i 阶最小花费,min(dp[i-1]+cost[i-1], dp[i-2]+cost[i-2])。楼顶不收费,答案 dp[n],时间 O(n)、空间 O(1)。
这道题到底在求什么
给一个数组 cost,下标 i 处的值是「离开第 i 阶」要付的钱。你可以从第 0 阶或第 1 阶起步(起步不花钱),每次向上走 1 阶或 2 阶,目标是花最少的钱爬到楼顶。这里有个最容易踩的坑:楼顶不收费。cost 只到最后一阶,站上楼顶不再「离开」任何台阶,所以不计费,答案是 dp[n] 而非 dp[n-1]。
为什么贪心每步挑便宜的会错
一个很自然的想法是贪心:每步都跳到眼前更便宜的那阶。但眼前省下的这一步,往往把你顶到后面只剩高价阶可踩。以 cost = [1,100,1,1,1,100,1,1,100,1] 为例,那几个 100 就是专门埋来惩罚短视选择的陷阱。
把所有路径枚举一遍当然不会错,但每步两个分支一路分叉,路径数随阶数指数膨胀,根本算不完。出路是记住「到每一阶的最小花费」,让后面的决策直接复用,而不是每次从头再拼。
dp 怎么定义,起步为什么是 0
定义 dp[i] 为「爬到第 i 阶所需的最小花费」。起点铺两个:dp[0] = 0、dp[1] = 0,因为题目允许从第 0 或第 1 阶零成本起步。要分清两件事——踏上某阶不花钱,离开某阶才按 cost 付费。所以「到第 i 阶」的花费只算一路上离开过的台阶费用,落脚的第 i 阶还没离开,不计。
转移为什么是两条来路取 min
站在第 i 阶回头看,上一步只可能来自两处:从第 i-1 阶走 1 阶上来,代价是「到 i-1 阶的最小花费」再加上离开它的 cost[i-1];或者从第 i-2 阶跨 2 阶上来,代价是「到 i-2 阶的最小花费」加 cost[i-2]。两条来路各自的最优都是子问题已经算好的,到第 i 阶的最优就是两者取更小:dp[i] = min(dp[i-1]+cost[i-1], dp[i-2]+cost[i-2])。
拿题目样例把表填出来
对着 cost = [1,100,1,1,1,100,1,1,100,1] 亲手填一遍最有感觉。起步 dp[0]=0、dp[1]=0。到第 2 阶:从第 1 阶来花 0+100=100,从第 0 阶跳 2 阶来花 0+1=1,取小的 dp[2]=1——第一个 100 就这样被绕开。接着 dp[3]=min(1+1, 0+100)=2,同法逐格上推,到 dp[9]=min(4+100, 4+1)=5、dp[10]=min(5+1, 4+100)=6,楼顶花费 6,正是答案。
复杂度与三个翻车点
从第 2 阶线性推到第 n 阶,每格只做一次比较,时间 O(n);dp[i] 只依赖前两项,用两个变量滚动即可,空间 O(1)。
三个高频错处:一是给楼顶也付了费,可楼顶根本不收费,答案是 dp[n];二是起步费设错,dp[0] 和 dp[1] 都该是 0;三是付错台阶——走到第 i 阶付的是「来路那一阶」的 cost(cost[i-1] 或 cost[i-2]),不是 cost[i]。
▶ 动画逐步走查(共 23 步)——想跟着动画一帧帧对照就展开
- 3记住这条转移式,下面每一格都在套它。
- 4上行是各阶离开费 cost(固定不动),下行 dp 待填。从最左边开始。
- 5可以从第 0 阶起步,起步不花钱:dp[0]=0。
- 6也可以从第 1 阶起步:dp[1]=0。两个起点都 0 花费。
- 7算 dp[2]:两条来路——从 1 阶走 1 步花 0+100=100,从 0 阶跳 2 步花 0+1=1。
- 8取较小的 1 填进 dp[2]。跳 2 步更省。
- 9算 dp[3]:两条来路——从 2 阶走 1 步花 1+1=2,从 1 阶跳 2 步花 0+100=100。
- 10取较小的 2 填进 dp[3]。走 1 步更省。
- 11算 dp[4]:两条来路——从 3 阶走 1 步花 2+1=3,从 2 阶跳 2 步花 1+1=2。
- 12取较小的 2 填进 dp[4]。跳 2 步更省。
- 13算 dp[5]:两条来路——从 4 阶走 1 步花 2+1=3,从 3 阶跳 2 步花 2+1=3。
- 14取较小的 3 填进 dp[5]。两条一样。
- 15算 dp[6]:两条来路——从 5 阶走 1 步花 3+100=103,从 4 阶跳 2 步花 2+1=3。
- 16取较小的 3 填进 dp[6]。跳 2 步更省。
- 17算 dp[7]:两条来路——从 6 阶走 1 步花 3+1=4,从 5 阶跳 2 步花 3+100=103。
- 18取较小的 4 填进 dp[7]。走 1 步更省。
- 19算 dp[8]:两条来路——从 7 阶走 1 步花 4+1=5,从 6 阶跳 2 步花 3+1=4。
- 20取较小的 4 填进 dp[8]。跳 2 步更省。
- 21算 dp[9]:两条来路——从 8 阶走 1 步花 4+100=104,从 7 阶跳 2 步花 4+1=5。
- 22取较小的 5 填进 dp[9]。跳 2 步更省。
- 23算 dp[10]:两条来路——从 9 阶走 1 步花 5+1=6,从 8 阶跳 2 步花 4+100=104。
- 24取较小的 6 填进 dp[10]。走 1 步更省。
- 25最右 dp[10]=6 就是爬到楼顶的最小花费。注意楼顶本身不收费。
⚠️ 容易写错的地方
✗ 错:给楼顶也付费
✓ 对:楼顶 step n 不收费,答案是 dp[n]
cost 只到 n-1
✗ 错:起步费设错
✓ 对:dp[0]=dp[1]=0
可从 0 或 1 阶 0 花费起步
✗ 错:付错台阶
✓ 对:走到 i 付的是来路那阶的 cost
cost[i-1] 或 cost[i-2]
完整代码(Python / C++ / Java)
Python
def minCostClimbingStairs(cost):
n = len(cost)
a, b = 0, 0 # dp[i-2], dp[i-1]
for i in range(2, n + 1):
a, b = b, min(b + cost[i-1], a + cost[i-2])
return bC++
int minCostClimbingStairs(vector<int>& cost){
int n = cost.size(), a = 0, b = 0;
for(int i = 2; i <= n; ++i){
int c = min(b + cost[i-1], a + cost[i-2]);
a = b; b = c;
}
return b;
}Java
int minCostClimbingStairs(int[] cost){
int n = cost.length, a = 0, b = 0;
for(int i = 2; i <= n; i++){
int c = Math.min(b + cost[i-1], a + cost[i-2]);
a = b; b = c;
}
return b;
}复杂度
时间
O(n)
一遍线性递推,每格 O(1)
空间
O(1)
只需前两项滚动
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 使用最小花费爬楼梯 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
为什么不能贪心地每步都跳到花费更小的台阶?+
贪心只看眼前一步,局部最省常把你逼到后面只能踩高价阶。像 cost 里那几个 100,就是专门惩罚短视选择的陷阱。动态规划记住「到每一阶的最小花费」,让每步决策都建立在子问题已经算好的最优解之上(这就是「最优子结构」),才不会被带偏。
答案是 dp[n] 还是 dp[n-1]?楼顶到底算不算费用?+
答案是 dp[n],楼顶不收费。cost 只到下标 n-1,付的永远是「离开某一阶」的费用;站上楼顶后不再离开任何台阶,所以那一下不计费。把答案取成 dp[n-1] 是最常见的差一错误。
它和爬楼梯 LeetCode 70 是什么关系?+
转移骨架一模一样,都由前两阶推来。区别只在:LeetCode 70 数走法总数,用加法把两条来路累加;本题求最小花费,用 min 取更省的那条来路。会了一题,另一题只需把加法换成取最小值。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄把 使用最小花费爬楼梯 一步步讲透(全站已上线 905 份讲透,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
把这道题真正拿下
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。