Easy

题目描述

假设你正在爬楼梯。需要 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 阶

提示:

  • 1 <= n <= 45

解题思路

这是一道经典的动态规划问题,实际上就是斐波那契数列的变形。

核心思路: 要到达第 n 阶楼梯,只能从第 n-1 阶爬 1 步,或从第 n-2 阶爬 2 步。因此状态转移方程为:f(n) = f(n-1) + f(n-2)

解法分析:

  1. 递归解法(不推荐): 直接按照递推关系实现,但会有大量重复计算,时间复杂度 O(2^n)

  2. 记忆化递归: 使用哈希表缓存已计算结果,避免重复计算,时间复杂度 O(n)

  3. 动态规划(推荐): 使用数组存储中间结果,自底向上计算,时间复杂度 O(n),空间复杂度 O(n)

  4. 空间优化的动态规划(最优): 由于只需要前两个状态,可以用两个变量代替数组,将空间复杂度优化到 O(1)

边界条件: f(1) = 1(只有一种方法),f(2) = 2(两种方法:1+1 或 2)

下面给出空间优化的动态规划解法,这是最优解。

代码实现

class Solution {
public:
    int climbStairs(int n) {
        if (n <= 2) return n;
        
        int prev2 = 1, prev1 = 2;
        for (int i = 3; i <= n; i++) {
            int curr = prev1 + prev2;
            prev2 = prev1;
            prev1 = curr;
        }
        return prev1;
    }
};
class Solution:
    def climbStairs(self, n: int) -> int:
        if n <= 2:
            return n
        
        prev2, prev1 = 1, 2
        for i in range(3, n + 1):
            curr = prev1 + prev2
            prev2, prev1 = prev1, curr
        
        return prev1
public class Solution {
    public int ClimbStairs(int n) {
        if (n <= 2) return n;
        
        int prev2 = 1, prev1 = 2;
        for (int i = 3; i <= n; i++) {
            int curr = prev1 + prev2;
            prev2 = prev1;
            prev1 = curr;
        }
        return prev1;
    }
}
var climbStairs = function(n) {
    if (n <= 2) return n;
    
    let prev2 = 1, prev1 = 2;
    for (let i = 3; i <= n; i++) {
        const curr = prev1 + prev2;
        prev2 = prev1;
        prev1 = curr;
    }
    return prev1;
};

复杂度分析

复杂度类型复杂度说明
时间复杂度O(n)需要计算从 3 到 n 的所有值
空间复杂度O(1)只使用常数个额外变量

相关题目