这是一道经典的动态规划问题,其核心思路与斐波那契数列类似。
问题分析:
假设跳上第 n
级台阶的跳法总数为 f(n)
。
- 基础情况:
- 若
n = 1
,只有1种跳法(跳1级),即f(1) = 1
; - 若
n = 2
,有2种跳法(1+1或直接跳2级),即f(2) = 2
。
- 若
- 递推关系:
跳上第n
级台阶的最后一步只有两种可能:- 从第
n-1
级台阶跳1级; - 从第
n-2
级台阶跳2级。
因此,f(n) = f(n-1) + f(n-2)
(与斐波那契数列递推公式一致)。
- 从第
算法实现:
1. 递归法(时间复杂度高,不推荐)
直接按递推公式递归计算,但会产生大量重复计算(如 f(n-2)
被计算多次)。
- 时间复杂度:O(2ⁿ)(指数级,效率极低)。
2. 动态规划(推荐)
用数组或变量存储中间结果,避免重复计算。
- 优化空间的动态规划:
只需记录前两项f(n-1)
和f(n-2)
,无需存储整个数组。python
def climb_stairs(n):
if n <= 2:
return n
a, b = 1, 2 # f(1)=1, f(2)=2
for _ in range(3, n+1):
a, b = b, a + b # 滚动更新前两项
return b
- 时间复杂度:O(n)(线性级,遍历一次即可)。
- 空间复杂度:O(1)(仅用常数空间)。
3. 矩阵快速幂或通项公式(进阶优化)
- 矩阵快速幂:将递推关系转化为矩阵乘法,时间复杂度优化至 O(log n)。
- 通项公式:利用斐波那契数列的数学公式直接计算,时间复杂度 O(1),但实际中因浮点数精度问题较少使用。
总结:
- 总跳法数量:符合斐波那契数列规律,即
f(n)
等于第n+1
个斐波那契数(以f(1)=1, f(2)=1
为基准的斐波那契数列)。 - 最优算法:动态规划(O(n) 时间 + O(1) 空间),适合面试中快速实现;若追求极致效率,可使用矩阵快速幂(O(log n))。
这类问题考察对递归、动态规划的理解,以及优化时间/空间复杂度的能力,在算法面试中非常常见。
矩阵快速幂是一种通过矩阵乘法和快速幂技巧优化线性递推问题时间复杂度的方法,尤其适用于斐波那契数列、台阶跳法等具有线性递推关系的场景。以下是具体实现步骤和代码示例:
一、核心原理
对于台阶跳法问题,递推公式为 f(n) = f(n-1) + f(n-2)
,可转化为矩阵乘法形式:
[f(n)f(n−1)]=[1110]×[f(n−1)f(n−2)] \begin{bmatrix} f(n) \\ f(n-1) \end{bmatrix} = \begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix} \times \begin{bmatrix} f(n-1) \\ f(n-2) \end{bmatrix} [f(n)f(n−1)]=[1110]×[f(n−1)f(n−2)]
记系数矩阵为 M=[1110] M = \begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix} M=[1110],则有:
[f(n)f(n−1)]=Mn−2×[f(2)f(1)] \begin{bmatrix} f(n) \\ f(n-1) \end{bmatrix} = M^{n-2} \times \begin{bmatrix} f(2) \\ f(1) \end{bmatrix} [f(n)f(n−1)]=Mn−2×[f(2)f(1)]
因此,计算 f(n) f(n) f(n) 等价于计算 Mn−2 M^{n-2} Mn−2,再与初始向量 [f(2)f(1)]=[21] \begin{bmatrix} f(2) \\ f(1) \end{bmatrix} = \begin{bmatrix} 2 \\ 1 \end{bmatrix} [f(2)f(1)]=[21] 相乘。
二、矩阵快速幂实现步骤
1. 矩阵乘法
定义两个 2x2 矩阵的乘法规则:
[abcd]×[efgh]=[ae+bgaf+bhce+dgcf+dh] \begin{bmatrix} a & b \\ c & d \end{bmatrix} \times \begin{bmatrix} e & f \\ g & h \end{bmatrix} = \begin{bmatrix} ae+bg & af+bh \\ ce+dg & cf+dh \end{bmatrix} [acbd]×[egfh]=[ae+bgce+dgaf+bhcf+dh]
2. 快速幂(二进制 exponentiation)
通过将指数 k k k 拆分为二进制(如 k=5=1012=4+1 k = 5 = 101_2 = 4 + 1 k=5=1012=4+1),减少乘法次数:
- 若 k k k 为偶数:Mk=(Mk/2)2 M^k = (M^{k/2})^2 Mk=(Mk/2)2
- 若 k k k 为奇数:Mk=M×(M(k−1)/2)2 M^k = M \times (M^{(k-1)/2})^2 Mk=M×(M(k−1)/2)2
3. 矩阵与向量乘法
用计算得到的 Mn−2 M^{n-2} Mn−2 乘以初始向量 [21] \begin{bmatrix} 2 \\ 1 \end{bmatrix} [21],结果的第一个元素即为 f(n) f(n) f(n)。
三、代码实现(Python)
python
def matrix_mult(a, b): | |
"""2x2矩阵乘法:a * b""" | |
return [ | |
[a[0][0]*b[0][0] + a[0][1]*b[1][0], # 第1行第1列 | |
a[0][0]*b[0][1] + a[0][1]*b[1][1]], # 第1行第2列 | |
[a[1][0]*b[0][0] + a[1][1]*b[1][0], # 第2行第1列 | |
a[1][0]*b[0][1] + a[1][1]*b[1][1]] # 第2行第2列 | |
] | |
def matrix_pow(mat, power): | |
"""矩阵快速幂:计算 mat^power""" | |
# 初始化为单位矩阵(类比数字乘法中的1) | |
result = [[1, 0], [0, 1]] | |
while power > 0: | |
if power % 2 == 1: | |
result = matrix_mult(result, mat) # 若当前位为1,乘入结果 | |
mat = matrix_mult(mat, mat) # 矩阵平方(对应二进制右移一位) | |
power //= 2 | |
return result | |
def climb_stairs_matrix(n): | |
"""用矩阵快速幂计算台阶跳法""" | |
if n <= 2: | |
return n | |
# 系数矩阵 M | |
M = [[1, 1], [1, 0]] | |
# 计算 M^(n-2) | |
M_pow = matrix_pow(M, n-2) | |
# 初始向量 [f(2), f(1)] = [2, 1],结果为 M_pow * [2, 1]^T 的第一个元素 | |
return M_pow[0][0] * 2 + M_pow[0][1] * 1 |
四、时间复杂度分析
- 矩阵乘法:每次 2x2 矩阵乘法耗时 O(1) O(1) O(1)(固定 4 次乘法和 4 次加法)。
- 快速幂迭代次数:指数 n−2 n-2 n−2 的二进制位数为 O(logn) O(\log n) O(logn),因此矩阵乘法执行 O(logn) O(\log n) O(logn) 次。
- 总时间复杂度:O(logn) O(\log n) O(logn),远优于递归法的 O(2n) O(2^n) O(2n) 和普通动态规划的 O(n) O(n) O(n)。
五、适用场景
矩阵快速幂适用于 递推关系固定且指数较大 的场景(如 n n n 高达 109 10^9 109 时),通过将线性递推转化为矩阵幂运算,实现对数级时间复杂度优化。
示例验证
- 当 n=3 n=3 n=3 时,M1=[1110] M^{1} = \begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix} M1=[1110],结果为 1∗2+1∗1=3 1*2 + 1*1 = 3 1∗2+1∗1=3(正确,3级台阶有3种跳法)。
- 当 n=5 n=5 n=5 时,M3=[3221] M^3 = \begin{bmatrix} 3 & 2 \\ 2 & 1 \end{bmatrix} M3=[3221],结果为 3∗2+2∗1=8 3*2 + 2*1 = 8 3∗2+2∗1=8(正确,5级台阶有8种跳法)。
通过矩阵快速幂,可高效解决大规模 n n n 的台阶跳法问题。