Leetcode - Climbing Stairs

来源:互联网 发布:rt809h编程器 编辑:程序博客网 时间:2024/06/07 03:57

Question

You are climbing a stair case. It takes n steps to reach to the top.

Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?


JavaCode

//版本一: 寻找递推公式,使用for循环统计不同的走法public int climbStairs(int n) {    if(n < 3) return n;    int fun = 0;    int fun1 = 2;    int fun2 = 1;    for(int i = 3; i <= n; ++i) {        fun = fun1 + fun2;//递推公式: f(n)=f(n-1)+f(n-2)        fun2 = fun1;//循环转移关系: f(n-2) <-- f(n-1)        fun1 = fun;//循环转移关系: f(n-1) <-- f(n)    }    return fun;}//版本二: 寻找递推公式,使用递归统计不同的走法public int climbStairs(int n) {    if(n < 3) return n;    return climbStairs(n-1) + climbStairs(n-2);}//版本三: 递归构造二叉树,叶子节点的个数即为不同的走法public int climbStairs(int n) {    return grow(n, 0);}private int grow(int n, int sum) {    //如果剩余2阶以上,继续生长子节点    if(n - 2 > 0)         sum = grow(n-2, sum);    //如果剩余1阶以上,继续生长子节点    if(n - 1 > 0)         sum = grow(n-1, sum);    //如果恰好剩余2阶或1阶,则到达叶子节点    if(n < 3)         sum++;    return sum;}

说明

  • 本题的抽象数学模型非常类似于斐波那契数列,如果n表示总的阶梯数,f(n)表示不同的走法,则有通项公式f(n)=f(n-1)+f(n-2)。这个公式可以这么理解,当走到第n-1阶时,再多走1阶就到了第n阶,所以f(n-1)构成了f(n)的一部分,类似的,当走到第n-2阶时,再一次走2阶(这一步只能这么走,如果分两次走,则会和f(n-1)的情况出现相同的走法),所以f(n-2)构成了f(n)的另一部分,又因为每一步只能走1阶或2阶,所以f(n)只能由这两种走法衍生出来。那么得到f(n)只与前两项相关,从而可以用循环替代递归,分别对应版本一和版本二的解法。

  • 版本三的思路是我最开始想到的方法,因为直观地来理解,除最后一步外每一步都有两种走法,所以可以用二叉树描述爬楼梯的过程。从第1阶开始,每走一步就生长出两个子节点,左子节点表示当前走1阶,右子节点表示当前走2阶,如此递归循环下去,最后一步可能是走1阶也可能是走2阶,当到达楼梯顶端时则得到叶子节点,且每个叶子节点代表一种走法,统计整棵树的叶子节点个数就得到了所有的不同走法。

  • 我们可以分析一下时间复杂度,版本一是O(n),版本二和三都约是O(2^n),由于使用递归会存在大量的重复计算,所以版本二和三的代码在n取较大值时运行会超时。实际上,还有一种时间复杂度为O(logn)的解法,利用了矩阵的幂和分治法的思想,可以参考博文计算斐波纳契数,分析算法复杂度。

0 0
原创粉丝点击