Climbing Stairs

Description:

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?

问题描述:

爬楼梯问题,楼梯总共有n级台阶,你可以每次爬1步台阶或者每次跳2步台阶,那么请问爬到n级台阶共有多少种方法。

解法一:

思路:

这个问题给人的第一感觉是用递归解决,要爬到第n级台阶处,那么自然是有两种情况构成的,在n-1级台阶处,可以直接爬1步;或者在第n-2级台阶处,跳2步爬上。思路简单,但是耗时间,耗空间,接下来的解法用动态规划解决。

Code:

public int climbStairs(int n){
        if(n == 1) return 1;
        if(n == 2) return 2;
        return climbStairs2(n-1) + climbStairs2(n-2);
    }

解法二:

思路:

之所以说这道题可以用动态规划解决,其实这道题和斐波拉契数列很想,动态规划的核心是两点,状态和状态转移方程。动态规划的范围很广,不局限于解决递归问题。
这里为了把动态规划的思路说清楚,我穷举下。
0.爬1级楼梯,有0种方法
1.爬1级楼梯,有一种方法。
2. 爬2级台阶,有2种方法
3. 爬3级台阶,可以是爬1步+爬(3-1)级台阶跳2步+爬(3-2)级台阶方法的总和为2+1=3
4. 爬4级台阶,可以是爬1步+爬(4-1)级台阶跳2步+爬(4-2)级台阶方法的总和为2+3=5
5. 爬5级台阶,可以是爬1步+爬(5-1)级台阶跳2步+爬(5-2)级台阶方法的总和为3+5=8
…….

看成数字序列就是 1 2 3 5 8 13 21 ….
明显是变初项的斐波拉契数列

我想这里我应该解释清楚了,既然斐波拉契数列可以用动态规划解决,那么这道题也可以。
这里的动态规划是避免了重复计算子问题,但是空间复杂度还可以降。

Code:

public int climbStairs3(int n){
        int[] dp = new int[n+1];
        dp[0] = 0;
        dp[1] = 1;
        dp[2] = 2;
        for(int i = 3;i <= n; i++){
            dp[i] = dp[i-1] + dp[i-2];
        }
        return dp[n];
    }

解法三:

思路:

在动态规划降空间复杂度的方法中,在这里有两种方法。这里先将滚动数组,所谓滚动数组这个名词说起来玄乎,其实就是不断对数组中存储的元素进行循环刷新,让数组的空间被滚动的利用。
这个题目里a[n] = a[n-1] + a[n-2] , 所以真正需要的就是3个变量。所以不要向解法二那样分配n+1维数组了,只需要int[3],然后利用 %(取模)运算符滚动刷新数组中的内容就可以了、

Code:

public int climbStairs4(int n){
        int[] dp = new int[3];
        dp[0] = 1;
        dp[1] = 1;

        for(int i = 2;i <= n; i++){
            dp[i % 3] = dp[(i-1) % 3] + dp[(i-2) % 3];
        }
        return dp[n % 3];
    }

解法四:

思路:

既然我知道只需要三个变量即可,那么回到问题本质,我就只用三个变量one_step_before two_step_before all_ways
one_step_before代表距离终点差一步时所有的方式
two_step_before代表距离终点差两步时所有的方式
all_ways代表去终点所有的方式

所以可以用依次赋值的方式,将one_step_before的值赋给two_step_before,那么two_step_before就唯一确定(本来的不确定态变为确定态), 将all_ways的值赋给one_step_before,那么得到更新的one_step_before。

all_ways = one_step_before + two_step_before;
two_step_before = one_step_before;
one_step_before = all_ways;

以上代码的次序很重要

Code:

public int climbStairs(int n) {
        //base case
        if(n <= 0) return 0;
        if(n == 1) return 1;
        if(n == 2) return 2;

        int one_step_before = 2;
        int two_step_before = 1;
        int all_ways = 0;

        for(int i = 2; i< n; i++){
            all_ways = one_step_before + two_step_before;
            two_step_before = one_step_before;
            one_step_before = all_ways;
        }

        return all_ways;

    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值