题目描述
思路解析
一句话答案:LeetCode 70 爬楼梯的标准解是动态规划递推 dp[i] = dp[i-1] + dp[i-2]:到第 i 阶的最后一步只能跨 1 或 2 阶,两类互斥穷尽,方案数相加。两个变量滚动,时间 O(n)、空间 O(1),本质是斐波那契。
爬楼梯到底在数什么
楼梯共 n 阶,每步只能上 1 阶或 2 阶,问从地面走到第 n 阶一共有多少种不同的走法。注意这是一道「数方案数」的题:答案是走法的总数,而不是最少步数,也不是某条具体路线。比如 n = 10 时答案是 89,意味着存在 89 条互不相同的上楼顺序。
为什么不能把所有走法枚举一遍
最直觉的思路是把每一步的选择都展开:每一步有跨 1 阶、跨 2 阶两个分支,一路分叉下去,走法总数随 n 指数级膨胀,逐条枚举根本数不完。慢的根源是重复劳动——无数条路线的后半段其实一模一样,却被一遍遍重数。
关键观察藏在「最后一步」上:不管前面怎么走,落到第 i 阶的最后一步只有两种可能——从第 i-1 阶跨 1 步上来,或从第 i-2 阶跨 2 步上来。于是「到第 i 阶的方法数」就落在「到 i-1 阶」和「到 i-2 阶」这两个更小的问题上,递推能写了。
dp 数组怎么定义,dp[0] 为什么是 1
定义 dp[i] 为「从地面走到第 i 阶的方法数」。起点要铺两个:dp[1] = 1,因为到第 1 阶只有跨一步这一种走法;dp[0] = 1,表示站在地面、一步没走也算一种方案。dp[0] 常被误设成 0,一旦设 0,dp[2] = dp[1] + dp[0] 就会漏掉「直接跨 2 阶」这条路,错误还会一路传染,整张表全部偏小。
为什么两条来路直接相加不重不漏
加法成立的依据是分类计数:按「最后一步跨几阶」把到达第 i 阶的所有走法分成两堆——最后跨 1 阶的,前半程恰好是一条到 i-1 阶的走法;最后跨 2 阶的,前半程恰好是一条到 i-2 阶的走法。两堆的最后一步不同,不可能有同一条走法被数两次;而最后一步只有这两种可能,也不会有走法被漏掉。这题是数方案不是求最优,转移用加法而不是 min 或 max——同一张递推表换成取最小值,就变成另一类问题了。
拿 n=10 把递推填一遍
亲手填一遍表就彻底通了。地面 dp[0] = 1,第 1 阶 dp[1] = 1。到第 2 阶:最后一步要么从第 1 阶跨 1、要么从地面跨 2,dp[2] = dp[1] + dp[0] = 2。往后每格都是前两格相加:dp[3] = 3、dp[4] = 5、dp[5] = 8,整串就是 1、1、2、3、5、8、13、21、34、55、89,到 dp[10] = 89,正是答案。滚动优化时只留最近两个数,用 a, b = b, a + b(把 a 换成旧的 b、b 换成两者之和)每轮向前挪一格,整张表根本不必存下来。
复杂度多少,和斐波那契什么关系
从 dp[2] 递推到 dp[n],每格只做一次加法,时间 O(n);又因为 dp[i] 只依赖前两项,不必存整个数组,用两个变量轮替即可,空间 O(1)。
递推式 dp[i] = dp[i-1] + dp[i-2] 加上 dp[0] = dp[1] = 1,正是斐波那契数列,所以爬楼梯常被叫作斐波那契的「面试皮肤」。边界上留意 n = 1 要能直接返回 1,循环从第 2 阶才开始。
▶ 动画逐步走查(文字版)——想跟着上方动画一帧帧对照就展开
记住这条转移式:到第 i 阶的方法数 = 到 i-1 阶的方法数 + 到 i-2 阶的方法数。下面每一格都在套它。
下行 dp 待填,列号 0..10 是阶数。从最左边的两个起点开始。
dp[0]=1:站在地面(还没爬)算 1 种方法,这是计数的起点。
dp[1]=1:到第 1 阶只有「走 1 步」这 1 种走法。两个起点都先定下来。
算 dp[2]:两条来路——从第 1 阶跨 1 步上来有 1 种,从第 0 阶跨 2 步上来有 1 种。这两批走法没有重复。
把两条来路相加:1 + 1 = 2,填进 dp[2]。到第 2 阶共有 2 种走法。
算 dp[3]:两条来路——从第 2 阶跨 1 步上来有 2 种,从第 1 阶跨 2 步上来有 1 种。这两批走法没有重复。
把两条来路相加:2 + 1 = 3,填进 dp[3]。到第 3 阶共有 3 种走法。
算 dp[4]:两条来路——从第 3 阶跨 1 步上来有 3 种,从第 2 阶跨 2 步上来有 2 种。这两批走法没有重复。
把两条来路相加:3 + 2 = 5,填进 dp[4]。到第 4 阶共有 5 种走法。
算 dp[5]:两条来路——从第 4 阶跨 1 步上来有 5 种,从第 3 阶跨 2 步上来有 3 种。这两批走法没有重复。
把两条来路相加:5 + 3 = 8,填进 dp[5]。到第 5 阶共有 8 种走法。
算 dp[6]:两条来路——从第 5 阶跨 1 步上来有 8 种,从第 4 阶跨 2 步上来有 5 种。这两批走法没有重复。
把两条来路相加:8 + 5 = 13,填进 dp[6]。到第 6 阶共有 13 种走法。
算 dp[7]:两条来路——从第 6 阶跨 1 步上来有 13 种,从第 5 阶跨 2 步上来有 8 种。这两批走法没有重复。
把两条来路相加:13 + 8 = 21,填进 dp[7]。到第 7 阶共有 21 种走法。
算 dp[8]:两条来路——从第 7 阶跨 1 步上来有 21 种,从第 6 阶跨 2 步上来有 13 种。这两批走法没有重复。
把两条来路相加:21 + 13 = 34,填进 dp[8]。到第 8 阶共有 34 种走法。
算 dp[9]:两条来路——从第 8 阶跨 1 步上来有 34 种,从第 7 阶跨 2 步上来有 21 种。这两批走法没有重复。
把两条来路相加:34 + 21 = 55,填进 dp[9]。到第 9 阶共有 55 种走法。
算 dp[10]:两条来路——从第 9 阶跨 1 步上来有 55 种,从第 8 阶跨 2 步上来有 34 种。这两批走法没有重复。
把两条来路相加:55 + 34 = 89,填进 dp[10]。到第 10 阶共有 89 种走法。
最右 dp[10]=89 就是爬到第 10 阶的总走法数。整张表其实就是斐波那契数列。
小输入先手算对齐。
两个高频追问。
参考代码
def climbStairs(n): a, b = 1, 1 # dp[i-2], dp[i-1] for _ in range(2, n + 1): a, b = b, a + b return b复杂度
- 时间:O(n),一遍线性递推,每格 O(1)
- 空间:O(1),只需前两项滚动
易错点
面试追问把动画讲成自己的话
追问为什么两条来路能直接相加而不会重复计数?
追问这张表为什么是斐波那契?
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
使用最小花费爬楼梯
LeetCode 746 · 简单 · 沿着 一维动态规划 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题