爬楼梯

753 字
4 分钟
爬楼梯

题目链接:70. 爬楼梯 - 力扣(LeetCode)

  • 难度:简单
  • 标签:动态规划、数学

动态规划(Dynamic Programming)入门#

Tip

什么是动态规划? 动态规划(DP)的核心在于将一个复杂的问题分解成若干个重叠的子问题,并将子问题的解存储起来,避免重复计算。它的本质是:分治 + 记忆化 = 动态规划

动态规划的四个基本步骤#

  1. 定义状态dp[i] 存放的是什么?(例如:到达第 i 阶的方法数)。
  2. 转移方程:大问题如何由小问题推导出来?(例如:dp[i] = dp[i-1] + dp[i-2])。
  3. 确定边界:最简单的情况(初始值)是什么?(例如:dp[1] = 1, dp[2] = 2)。
  4. 计算顺序:自顶向下(递归+记忆化)或自底向上(循环迭代)。

题目描述#

Note

原题说明: 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。每次你可以爬 12 个台阶。你有多少种不同的方法可以爬到楼顶呢?

示例#

  • 输入: n = 2 -> 输出: 2(1+1 或 2)
  • 输入: n = 3 -> 输出: 3(1+1+1 或 1+2 或 2+1)

方案:滚动数组优化(动态规划)#

核心思路: 要到达第 n 阶,最后一步只有两种可能:

  • 从第 n-1 阶跨 1 步上来(共有 f(n-1) 种方法)。
  • 从第 n-2 阶跨 2 步上来(共有 f(n-2) 种方法)。 因此,状态转移方程为:f(n)=f(n1)+f(n2)f(n) = f(n-1) + f(n-2)。这正是著名的斐波那契数列。

源码实现#

class Solution {
public:
int climbStairs(int n) {
if (n <= 1) return 1;
// 使用三个变量进行滚动更新,将空间复杂度降至 O(1)
int a = 1; // f(n-2)
int b = 1; // f(n-1)
int c = 0; // f(n)
for (int i = 2; i <= n; ++i) {
c = a + b; // 当前阶 = 前两阶之和
a = b; // 窗口向右滚动
b = c;
}
return b;
}
};

复杂度分析#

  • 时间复杂度O(n)O(n)。我们只需进行一次线性循环即可计算出结果。
  • 空间复杂度O(1)O(1)。我们使用了“滚动数组”技巧,只保存了前两个状态,而非维护一整个 vector<int> dp(n)

常见问答#

Q:为什么不用纯递归? A:纯递归会产生大量的重复计算(如计算 f(5) 需要 f(4)f(3),计算 f(4) 又需要 f(3)…)。这会导致时间复杂度爆炸(指数级 O(2n)O(2^n)),当 n>40n > 40 时基本会超时。

Q:如果每次可以爬 1、2、3 步呢? A:同理推导出方程 f(n)=f(n1)+f(n2)+f(n3)f(n) = f(n-1) + f(n-2) + f(n-3),只需要增加一个初始化状态即可。


总结#

  • 状态转移是核心:找到“最后一步”的逻辑,就能写出方程。
  • 空间优化:当当前状态只依赖于前几个固定状态时,用变量替代数组是极佳的性能优化。
Important

爬楼梯是动态规划最经典的入门题。理解了它的分治思想,你就跨过了学习高级算法的第一道门槛!

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

爬楼梯
https://firefly-7a0.pages.dev/posts/leetcode_notes/70climbing-stairs/
作者
lonelystar
发布于
2025-10-18
许可协议
CC BY-NC-SA 4.0
最后更新于 2025-10-18,距今已过 193 天

部分内容可能已过时

评论区

Profile Image of the Author
LonelyStar
Hello, I'm LonelyStar.
公告
欢迎来到我的博客!
音乐
封面

音乐

暂未播放

0:00 0:00
暂无歌词
分类
标签
站点统计
文章
119
分类
11
标签
346
总字数
226,548
运行时长
0
最后活动
0 天前

目录