一、题目
假设你正在爬楼梯。需要 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 阶
二、求解
由于每次可以爬一阶楼梯
也可以爬两阶楼梯
,所以如果要爬到第N阶楼梯,其方案就有:
- 从第N-1阶爬1阶到N
- 从第N-2阶爬2阶到N
所以我们会发现规律为:f(n)=f(n-2)+f(n-1)
而这,正符合斐波那契数列,所以其实这就是一道斐波那契数列的变形题。解法如下:
const climbStairs = function(n) {
if (n < 2) {
return 1
}
let res;
let first = 1, second = 1;
for (let i=2; i<=n; ++i) {
res = first + second;
first = second
second = res
}
return res
};
三、斐波那契数列算法
求解斐波那契数列的算法有很多种,下面进行一下总结
1、递归方法
递归法是最简单的求解斐波那契数列的算法,其代码如下:
function fn(n) {
if (n < 2) {
return 1
}
return fn(n-2)+f(n-1)
}
但是我们会发现这种算法,在递归过程中进行了不少不必要的重复计算,如:
f(5) -> f(4) -> f(3) -> f(2) -> f(1)
-> f(0)
-> f(1)
-> f(2) -> f(1)
-> f(0)
-> f(3) -> f(2) -> f(1)
-> f(0)
-> f(1)
可见,这个算法并不够高效,甚至在N大的时候,会有爆栈的问题
2、尾递归方法
尾递归是指函数末尾调用只调用函数本身
的一种递归方式,尾递归可被编译器进行优化,从而比普通递归方式具有更好的时空效率。
function f(first, second, n) {
if (n < 2) {
return 1
}
if (n === 2) {
return first + second
}
return f(second, first + second, n - 1)
}
3、循环方法
不利用递归,直接循环求解
function f(n) {
if (n < 2) {
return 1
}
let res
let first = 1, second = 1
for (let i=2; i<=n; ++i) {
res = first + second
first = second
second = res
}
return res
}