愿你坚持不懈,努力进步,进阶成自己理想的人

—— 2017.09, 写给3年后的自己

LeetCode - 爬楼梯

一、题目

假设你正在爬楼梯。需要 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
}