力扣第 70 题:爬楼梯问题(Climbing Stairs)

力扣第 70 题:爬楼梯问题(Climbing Stairs)

一、题目描述

假设你正在爬楼梯,需要爬到第 nnn 级台阶。每次可以爬 111222 级台阶。有多少种不同的方法可以爬到楼顶?

输入:一个正整数 nnn
输出:一个整数,表示不同的方法数。


二、解题思路

这个问题可以用 递归 + 记忆化 的方式解决,本质是一个 动态规划问题

1. 状态定义

定义 dp[i]dp[i]dp[i] 表示爬到第 iii 级台阶的方法数。

2. 状态转移方程

每次可以选择爬 111 级或 222 级台阶,因此可以得到递推关系:
dp[i]=dp[i−1]+dp[i−2] dp[i] = dp[i-1] + dp[i-2] dp[i]=dp[i1]+dp[i2]

3. 初始条件

  • i=1i=1i=1 时,只有一种方法爬到第一级:直接爬 111 级。因此,dp[1]=1dp[1] = 1dp[1]=1
  • i=2i=2i=2 时,有两种方法爬到第二级:爬 1+11+11+1 或直接爬 222。因此,dp[2]=2dp[2] = 2dp[2]=2

三、递归 + 记忆化实现

我们通过递归来解决这个问题,同时使用一个数组 memo 来存储已经计算过的结果,避免重复计算。

完整代码(C 语言)

#include 
#include 

// 递归函数,使用记忆化存储
int dfs(int n, int* memo) {
    if (n == 0) {
        return 1; // 到达楼顶的方法数
    } else if (n < 0) {
        return 0; // 无效路径
    }
    if (memo[n] != -1) {
        return memo[n]; // 如果已经计算过,直接返回
    }
    // 递归计算
    memo[n] = dfs(n - 1, memo) + dfs(n - 2, memo);
    return memo[n];
}

// 主函数
int climbStairs(int n) {
    // 动态分配 memo 数组,并初始化为 -1
    int* memo = (int*)malloc((n + 1) * sizeof(int));
    for (int i = 0; i <= n; i++) {
        memo[i] = -1;
    }

    // 调用递归函数
    int result = dfs(n, memo);

    // 释放动态内存
    free(memo);

    return result;
}

int main() {
    int n;
    printf("请输入楼梯的级数:");
    scanf("%d", &n);

    int result = climbStairs(n);
    printf("共有 %d 种不同的方法可以爬到第 %d 级台阶。\n", result, n);

    return 0;
}

四、代码详解

1. dfs 函数

递归函数负责计算从当前台阶爬到楼顶的方法数:

  • 边界条件
    • n=0n = 0n=0 时,返回 111,表示当前路径有效。
    • n<0n < 0n<0 时,返回 000,表示当前路径无效。
  • 记忆化查询
    • 如果 memo[n] != -1,直接返回存储的值。
  • 递归公式
    • dfs(n)=dfs(n−1)+dfs(n−2)dfs(n) = dfs(n-1) + dfs(n-2)dfs(n)=dfs(n1)+dfs(n2)

2. memo 的作用

memo 数组存储每一级台阶的方法数,避免了重复递归,提高了效率。

3. 主函数逻辑

  • 初始化 memo 数组为 -1
  • 调用递归函数 dfs(n, memo)
  • 释放 memo 动态内存,避免内存泄漏。

五、运行示例

输入:

请输入楼梯的级数:5

输出:

共有 8 种不同的方法可以爬到第 5 级台阶。

运行结果符合预期。


六、时间复杂度和空间复杂度分析

时间复杂度

使用记忆化递归,时间复杂度为 O(n)O(n)O(n),因为每一级台阶的方法数只会被计算一次。

空间复杂度

  • 递归调用栈的深度为 O(n)O(n)O(n)
  • memo 数组需要 O(n)O(n)O(n) 的空间存储结果。

总的空间复杂度为 O(n)O(n)O(n)


七、总结

通过递归结合记忆化存储,成功解决了爬楼梯问题。代码清晰、结构简单,并具有以下优点:

  1. 避免了重复计算,性能优于纯递归。
  2. 逻辑清晰,容易理解。

如果对递归不熟悉,也可以通过 迭代法动态规划表 实现,进一步优化空间复杂度。有关更多动态规划问题,欢迎继续关注!

你可能感兴趣的:(力扣第 70 题:爬楼梯问题(Climbing Stairs))