跳台阶基础版、改进版(不能连续跳2阶)

算法 跳台阶基础版、改进版(不能连续跳2阶)

@author:Jingdai
@date:2020.11.15

跳台阶(青蛙跳)是一个非常经典的算法问题,前几天看面试题看到一个跳台阶的改进版(不能连续跳2个台阶),现总结一下。

在介绍改进版解法之前先复习一下基础版,不想看的可以直接跳到改进版部分。

基础版

题目描述

有一个 n 阶的楼梯,你从最下面往上跳,每次可以跳1阶或2阶,有多少种方法可以跳到楼顶?

思路及代码

这个基础版很简单,对于第 n 阶,你只有两种方式跳上去:

  1. 从 n-1 阶跳1阶跳上去
  2. 从 n-2 阶跳2阶跳上去

所以就可以得到递推式:

在这里插入图片描述

然后可以利用递归方式求解或利用dp方式求解。看下面的代码:

  • 递归方式(不推荐,复杂度高,n较大时容易超时)

    public int jumpStairs(int n) {
           
           
        if (n <= 3)
            return n;
        return jumpStairs(n-1) + jumpStairs(n-2);
    }
    
  • dp方式

    public int jumpStairs(int n) {
           
           
        if (n <= 3)
            return n;
        int[] dp = new int[n];
        for (int i = 0; i < n; i++) {
           
           
            if (i <= 2) {
           
           
                dp[i] = i+1;
            } else {
           
           
                dp[i] = dp[i-1] + dp[i-2];
            }
        }
        return dp[dp.length-1];
    }
    

同时发现 dp 时只需要最后一个n的结果,所以可以优化一下空间复杂度,得到如下的代码:

扫描二维码关注公众号,回复: 12814220 查看本文章
  • 优化dp

    public int jumpStairs(int n) {
           
           
        if (n <= 3)
            return n;
    
        int prePre = 2;
        int pre = 3;
        int cur = 5;
        for (int i = 4; i <= n; i++) {
           
           
            cur = prePre + pre;
            prePre = pre;
            pre = cur;
        }
        return cur;
    }
    

同时,你会发现这个递归式就是斐波那契数列的式子,所以也可以直接用斐波那契数列的公式直接进行计算。

改进版

题目描述

题目基本一样,有一个 n 阶的楼梯,你从最下面往上跳,每次可以跳1阶或2阶,但是不能连续跳两次2阶,有多少种方法可以跳到楼顶?

思路及代码

利用之前基础版的思路,对于第 n 阶,你只有两种方式跳上去:

  1. 从 n-1 阶跳1阶跳上去
  2. 从 n-2 阶跳2阶跳上去(同时 n-2 阶必须是跳 1 阶跳上去的)

这里多了一个限制:从 n-2 阶跳 2 阶跳到 n 阶的 n-2 阶状态必须是从 n-3 阶跳1阶跳到 n-2 阶的。所以,这里我们动态规划不仅要保存跳到第 i 阶的所有方法数,还要保存最后一步通过跳 1 阶跳到第 i 阶的方法数。这里用 f(n) 表示跳到第 n 阶的总方法数,用 g(n) 表示最后一步跳一阶跳到第 n 阶的方法数,这样就得到递推式:

在这里插入图片描述

根据此就可以写代码了,看下面的代码片段。

public int modifiedJumpStairs(int n) {
     
     
        
    if (n <= 3)
        return n;

    // first total methods number
    // second last step is one step methods number
    int[][] dp = new int[n][2];

    dp[0][0] = 1; 
    dp[0][1] = 1;
    dp[1][0] = 2;
    dp[1][1] = 1;
    dp[2][0] = 3;
    dp[2][1] = 2;

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

我们再细心观察上面的递推式。

在这里插入图片描述

如图,递推式进行代换后可以更加简单。根据推出的结论,可以将二维数组改成一维数组,看下面的代码片段。

public int modifiedJumpStairs(int n) {
     
     

    if (n <= 3)
        return n;

    int[] dp = new int[n];

    for (int i = 0; i < n; i++) {
     
     
        if (i <= 2) {
     
     
            dp[i] = i+1;
        } else {
     
     
            dp[i] = dp[i-1] + dp[i-3];
        }
    }
    return dp[dp.length-1];
}

当然,上面代码还可以优化,因为只需要最后一个为 n 的结果,前面的都不需要,故可以把空间复杂度优化为 O(1) ,如下代码。

public int modifiedJumpStairs(int n) {
     
     

    if (n <= 3)
        return n;

    int prePrePre = 1;
    int prePre = 2;
    int pre = 3;
    int cur = 4;
    for (int i = 4; i <= n; i++) {
     
     
        cur = pre + prePrePre;
        prePrePre = prePre;
        prePre = pre;
        pre = cur;
    }

    return cur;
}

猜你喜欢

转载自blog.csdn.net/qq_41512783/article/details/109711869