【每天学习一点算法 2025/12/25】爬楼梯

每天学习一点算法 2025/12/25

题目:爬楼梯

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 12 个台阶。你有多少种不同的方法可以爬到楼顶呢?

爬楼梯是一道十分经典的动态规划题目,我记得大学老师还讲过这道题,虽然已经忘的差不多了,我们首先来分析这题目,我们先从小数推导规律,设 fn(i) = 爬到第i阶的方法数

  • 爬 1 阶楼梯:只有一种方法,fn(1) = 1

  • 爬 2 阶楼梯:有 1+12两种方法, fn(2) = 2

  • 爬 3 阶楼梯:我们换一个思考方式,如果我们登上了第 3 阶楼梯的最后一步爬了 1 个台阶,那这种爬 3 阶楼梯的方法就和爬 2 阶楼梯的方法一样,如果最后一步爬了 2 个台阶,那这种爬 3 阶楼梯的方法就和爬 1 阶楼梯的方法一样。这两种爬最后一步的方法加在一起就是爬 3 阶的楼梯的方法数,

    fn(3) = f(2) + f(1) = 3

  • 爬 n 阶楼梯:从这个爬 3 阶楼梯的分析,我们很容易得出,爬 n 阶楼梯的方法就是,爬 n - 1 阶楼梯(最后一步是爬 1 个台阶)的方法加上爬 n - 2 阶楼梯(最后一步是爬 2 个台阶)的方法,fn(n) = fn(n - 1) + fn(n - 2)

分析得出了最终的公式: fn(n) = fn(n - 1) + fn(n - 2)

  1. 最容易想到的就是递归

    typescript 复制代码
    function climbStairs(n: number): number {
       if (n === 1) return 1
       if (n === 2) return 2
       return climbStairs(n - 1) + climbStairs(n - 2)
    };

    此法虽然很容易想到但是数字太大的时候会超时,而且存在大量的重复运算,比如我们在计算爬 5 阶楼梯和爬 4 阶的方法时,都会计算爬 3 阶楼梯的方法。

  2. 上面的递归存在重复计算,我们可以用记忆化递归的方法,用一个数组存储已经计算过的结果,这样就可以有效的减少时间复杂度了

    typescript 复制代码
    function climbStairs(n: number): number {
      const memoSet: number[] = [1, 1, 2] // 初始填入 0 1 2 阶的爬楼方法数
      function auxiliary (n: number, memo: number[]): number {
        // 如果已有爬楼的计算结果直接取出不再重复递归
        if (memo[n]) return memo[n]
        // 递归计算爬楼方法并存储到记忆数组中
        memo[n] = auxiliary(n - 1, memo) + auxiliary(n - 2, memo)
        return memo[n]
      }
      // 传入记忆数组
      return auxiliary(n, memoSet)
    };
  3. 接下来讲一下动态规划的解题方法,动态规划(Dynamic Programming,简称 DP)核心是用空间换时间,避免重复计算,本质是:把一个复杂的大问题,拆解成若干个可解决的、不重复的小问题,先解决小问题并记录答案(存起来),再用小问题的答案推导大问题的答案。

    什么意思呢?

    • 递归是从目标值递归拆解成小问题,从目标 n 递归拆解成 n-1n-2
    • 动态规划是从最小的初始条件开始,一步步算到目标值(比如从 i=3 算到 i=n
    typescript 复制代码
    function climbStairs(n: number): number {
      // 处理边界 1 2 阶楼梯爬法
      if (n <= 2) return n;
      const memoSet: number[] = [1, 1, 2] // 初始填入 0 1 2 阶的爬楼方法数
      // 循环计算n阶爬楼方法
      for (let i = 3; i <= n; i++) {
        memoSet[i] = memoSet[i - 1] + memoSet[i - 2]
      }
      // 返回计算结果
      return memoSet[n]
    };
  4. 上面的方法我们看出,前面已经用过的数据其实已经可以丢弃了,那我们还可以优化一下空间复杂度,用两个变量存储 n - 1n - 2 阶的方法数。

    typescript 复制代码
    function climbStairs(n: number): number {
    	// 处理边界 1 2 阶楼梯爬法
      if (n <= 2) return n;
      let i = 1 // n - 2 初始为1阶楼梯爬法
      let j = 2 // n - 3 初始为2阶楼梯爬法
      let current = 0 // 存储当前阶的方法数
      // 循环计算爬 n 阶方法数
      for (let k = 3; k <= n; k++) {
        current = i + j
        i = j
        j = current
      }
      return current
    };

题目来源:力扣(LeetCode)

相关推荐
知乎的哥廷根数学学派4 分钟前
基于数据驱动的自适应正交小波基优化算法(Python)
开发语言·网络·人工智能·pytorch·python·深度学习·算法
非凡ghost5 分钟前
Wireshark中文版(网络抓包工具)
网络·windows·学习·测试工具·wireshark·软件需求
ADI_OP21 分钟前
ADAU1452的开发教程10:逻辑算法模块
算法·adi dsp中文资料·adi dsp·adi音频dsp·adi dsp开发教程·sigmadsp的开发详解
xingzhemengyou135 分钟前
C语言 查找一个字符在字符串中第i次出现的位置
c语言·算法
wdfk_prog2 小时前
[Linux]学习笔记系列 -- [driver]base
linux·笔记·学习
am心2 小时前
学习笔记-套餐接口
笔记·学习
小六子成长记2 小时前
【C++】:搜索二叉树的模拟实现
数据结构·c++·算法
汉克老师3 小时前
GESP2025年9月认证C++二级真题与解析(编程题1(优美的数字))
c++·算法·整除·枚举算法·求余·拆数
科技林总3 小时前
【系统分析师】3.6 操作系统
学习
Zevalin爱灰灰3 小时前
现代控制理论——第二章 系统状态空间表达式的解
线性代数·算法·现代控制