题目描述
假设你正在爬楼梯。需要 n
阶你才能到达楼顶。
每次你可以爬 1
或 2
个台阶。你有多少种不同的方法可以爬到楼顶呢?
示例 1:
输入:n = 2
输出:2
解释:有两种方法可以爬到楼顶。
1. 1 阶 + 1 阶
2. 2 阶
示例 2:
输入:n = 3
输出:3
解释:有三种方法可以爬到楼顶。
1. 1 阶 + 1 阶 + 1 阶
2. 1 阶 + 2 阶
3. 2 阶 + 1 阶
解题思路
这道题的目标是解决经典的"爬楼梯"问题,即给定楼梯的总阶数 n
,每次只能爬 1 或 2 阶,求总共有多少种不同的爬法。
背景知识:
- 爬楼梯问题与斐波那契数列密切相关,
f(n) = f(n-1) + f(n-2)
,初始条件为f(1) = 1, f(2) = 2
。 - 通过矩阵快速幂,可以在对数时间内求解斐波那契数列问题,利用状态转移矩阵:Q=[1110]Q=[1110] 斐波那契数列可以表示为:Fibonacci(n)=Q(n−1)[0][0]Fibonacci(n)=Q(n−1)[0][0]
源码实现
class Solution {
public int climbStairs(int n) {
// 定义状态转移矩阵 Q
int[][] q = {{1, 1}, {1, 0}};
// 计算矩阵 Q 的 n 次幂,得到爬楼梯的结果
int[][] res = pow(q, n);
// 返回结果矩阵的左上角元素,即 f(n)
return res[0][0];
}
// 矩阵快速幂方法
public int[][] pow(int[][] a, int n) {
// 初始化单位矩阵 I,用于保存中间结果
int[][] ret = {{1, 0}, {0, 1}};
while (n > 0) {
// 如果 n 是奇数,累乘当前矩阵
if ((n & 1) == 1) {
ret = multiply(ret, a);
}
// 更新矩阵 a 为其自身的平方
a = multiply(a, a);
// n 右移一位,相当于整除 2
n >>= 1;
}
// 返回结果矩阵
return ret;
}
// 矩阵乘法方法
public int[][] multiply(int[][] a, int[][] b) {
// 初始化结果矩阵
int[][] c = new int[2][2];
// 两个 2x2 矩阵逐元素相乘并累加
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
c[i][j] = a[i][0] * b[0][j] + a[i][1] * b[1][j];
}
}
// 返回乘积矩阵
return c;
}
}
复杂度分析
时间复杂度:
- 矩阵乘法复杂度:
- 两个 2x2 矩阵相乘需要进行常数次(4 次)乘法和加法操作,时间复杂度为 O(1)O(1)。
- 矩阵快速幂复杂度:
- 快速幂的时间复杂度为 O(logn)O(logn),因为每次将
n
除以 2,最多需要 O(logn)O(logn) 次矩阵平方操作。
- 快速幂的时间复杂度为 O(logn)O(logn),因为每次将
- 总复杂度:
- 因此,算法的时间复杂度为:O(logn)O(logn)
空间复杂度:
- 使用了两个 2x2 的矩阵
ret
和a
,以及一个临时矩阵c
,因此空间复杂度为常数 O(1)O(1)。