青蛙跳台阶的相关问题

青蛙跳台阶的相关问题

问题一:青蛙一次只能跳 1 个台阶或者 2 个台阶, 计算从 0 台阶跳到 n 台阶有多少跳法,也就是的路径种类总和。

import java.util.HashMap;

public class StepJump {
    // 当青蛙只能跳 1 个台阶或者 2 个台阶, 计算从 0 台阶跳到 n 台阶的路径种类总和
    // 这个类似斐波那契数列 1 1 2 3 5 8 13
    // f(0)=1, f(1)=1, f(2)=f(0)+f(1),[其中f(0)表示从0阶直接跳到2阶] f(3)=f(1)+f(2)
    // f(3)=f(1)+f(2)的解释:[先跳到1阶的路径种类(然后直接跳到3阶)+先跳到2阶的路径种类(然后直接跳到3阶)]
    private static int fun1(int n) {
        if(n < 2)
            return 1;
        // [先跳到n-1阶的路径种类(然后直接跳到n阶)+先跳到n-2阶的路径种类(然后直接跳到n阶)]
        return fun1(n-1)+fun1(n-2); // 递归
    }
    // 避免重复计算,可用一个 HashMap 存储计算过的值,防止重复计算。
    private static int fun2(int n, HashMap<Integer, Integer> map) {
        if(n < 2)
            return 1;
        // 如果map包含 n 对应的值,直接返回
        if(map.containsKey(n))
            return map.get(n);
        // 递归求值,和fun1()同样道理
        int first = fun2(n-1, map);
        int second = fun2(n-2, map);
        int sum = first + second;
        // 储存值,方便下次寻找
        map.put(n, sum);
        return sum;
    }
    // 利用循环计算,效率更高
    private static int fun3(int n) {
        if(n < 2)
            return 1;
        int first = 1, second = 1, sum = 0;
        while(n-- >= 2) {
            sum = first + second;
            first = second;
            second = sum;
        }
        return sum;
    }
    public static void main(String[] args) {
        int  n = 40;
        long time = System.nanoTime();
        System.out.println(fun1(n));
        System.out.println("递归时间:" + (System.nanoTime() - time));
        time = System.nanoTime();
        System.out.println(fun2(n, new HashMap<Integer, Integer>()));
        System.out.println("HashMap时间:" + (System.nanoTime() - time));
        time = System.nanoTime();
        System.out.println(fun3(n));
        System.out.println("循环时间:" + (System.nanoTime() - time));
    }
}
/* Code Running Results:(每次结果可能不同)
 * 165580141
 * 递归时间:347549100
 * 165580141
 * HashMap时间:114000
 * 165580141
 * 循环时间:21000
 */

问题二:青蛙一次能跳 1 到 n 个台阶, 计算从 0 台阶跳到 n 台阶有多少跳法,也就是的路径种类总和。

public class StepJumpTwo {
    // 青蛙一次能跳 1 到 n 个台阶, 计算从 0 台阶跳到 n 台阶的路径种类总和
    // f(n)  = f(n-1)+f(n-2)+......+f(1)+f(0)------a式子
    // f(n-1)= f(n-2)+f(n-3)+......+f(1)+f(0)------b式子
    // (a式子)-(b式子)得  f(n)-f(n-1)=f(n-1)
    // 最终得到 f(n)=2*f(n-1)的等比数列,该等比数列为2^(n-1)
    private static int fun(int n){
        if(n < 2)
            return 1;
        return 1<<(n-1);  // 位运算,速度更快
    }
    public static void main(String [] args){
        System.out.println(fun(10));
    }
}
/* Code Running Results:
 * 512
 */

问题三:青蛙一次能跳 1 到 m 个台阶, 计算从 0 台阶跳到 n 台阶有多少跳法,也就是的路径种类总和。

public class StepJumpThree {
    // 青蛙一次能跳 1 到 m 个台阶, 计算从 0 台阶跳到 n 台阶的路径种类总和

    // 情况1 n <= m 时,也就回到了问题二 f(n)=2*f(n-1), 等比数列为2^(n-1)

    // 情况2 当 n-1 = m 时
    // f(n)  = f(n-1)+f(n-2)+......+f(2)+f(1) 接下所有的计算又回到情况1
    //       = 2*f(n-2)+2*f(n-3)+......+2*f(1)+f(1)
    //       = ......
    //       = 2^(n-1)-1 (f(n)=2*f(n-1)的等比数列[2^(n-1)]的前 n-1 项和[2^(n-1)-1]

    // 情况3 当 n-1 > m 时
    // f(n)  = f(n-1)+f(n-2)+......+f(n-m+1)+f(n-m)------a式子
    // f(n-1)= f(n-2)+f(n-3)+......+f(n-m)+f(n-1-m)------b式子
    // (a式子)-(b式子)得  f(n)-f(n-1)=f(n-1)-f(n-1-m)
    // 最终得到 f(n)=2*f(n-1)-f(n-1-m)

    private static int fun(int n, int m){
       if(n < 2)
           return 1;
       if(n <= m)     // 情况1
           return 1<<(n-1);
       if(n-1 == m)   // 情况2
           return (1<<(n-1))-1;
        // 情况3
       return 2*fun(n-1, m)+fun(n-1-m, m);
    }
    public static void main(String [] args){
        System.out.println(fun(1, 5));  // n < 2
        System.out.println(fun(4, 5));  // 情况1
        System.out.println(fun(6, 5));  // 情况2
        System.out.println(fun(7, 5));  // 情况3
    }
}
/* Code Running Results:
 * 1
 * 8
 * 31
 * 63
 */
posted @ 2020-10-31 10:44  狡猾的狐狸科  阅读(155)  评论(0编辑  收藏  举报