一、题目描述:
leetcode70题:爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
示例 1:
输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
1. 1 阶 + 1 阶
2. 2 阶
示例 2:
输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
1. 1 阶 + 1 阶 + 1 阶
2. 1 阶 + 2 阶
3. 2 阶 + 1 阶
二、思路分析:
解法1:动态规划
假设n = 3,需要爬3级到楼顶。由题意可知,可以爬1个或是2个台阶,总共3种走法,这刚好是n=2走法加上n=1走法:
n=2有2种:
- 1 阶 + 1 阶
- 2 阶
n=1有1种: - 1 阶
通过归纳总结推导出动态规划的DP方程:
f(n) = f(n-1) + f(n-2)。
下面我们来讨论边界条件。我们是从第 0 级开始爬的,所以从第 0 级爬到第 0 级我们可以看作只有一种方案,即 f(0) = 1;从第 0 级到第 1 级也只有一种方案,即爬一级,f(1) = 1。这两个作为边界条件就可以继续向后推导出第 n 级的正确结果。我们不妨写几项来验证一下,根据转移方程得到 f(2) = 2,f(3) = 3,f(4) = 5,……,我们把这些情况都枚举出来,发现计算的结果是正确的。
复杂度分析:
- 时间复杂度:O(n),循环执行 n 次,因此时间复杂度为O(n)。
- 空间复杂度:O(1),计算第n级的走法,只需记录n-1和n-2两个数的空间,空间复杂度是线性的,所以为O(1)。
解法2:公式
n较小时,使用上述动态规划效率很不错,但n变大时,就需要考虑减小时间复杂度,需要更好的解决方案。
n代入具体的数值进行如下推导:
输入 1: 输出 1
输入 2: 输出 2
输入 3: 输出 3
输入 4: 输出 5
输入 5: 输出 8
......
咦,目前相当满足斐波那契数列!!!
查一查它的通项公式:
复杂度分析:
- 时间复杂度:O(logn),这里需要考虑Math.pow方法的影响。
- 空间复杂度:O(1),没有产生额外空间开销。
三、AC 代码:
动态规划的代码
var climbStairs = function(n) {
let dp = [];
dp[0] = 1;
dp[1] = 1;
for(let i = 2;i <= n;i++) {
dp[i] = dp[i-1] + dp[i-2];
}
return dp[n];
};
公式法的代码
// 公用常量
const sqrt5 = Math.sqrt(5);
var climbStairs = function(n) {
// 斐波那契数列
return (Math.pow((1 + sqrt5) / 2, n + 1) - Math.pow((1 - sqrt5) / 2, n + 1))/sqrt5
};
四、总结:
爬楼梯是leetcode经典动态规划题目,上述2种解法,我们主要是需要学习掌握动态规划。我们用动态规划来解题时,关键是推导出DP方程和确定DP边界状态。公式法是扩展学习斐波那契数列,是进阶解法,能够将时间复杂度降为O(logn)。
本文正在参与「掘金 3 月闯关活动」,点击查看活动详情