JavaSE习题 青蛙跳台阶问题

题目: 一只青蛙一次可以跳上 1 级台阶,也可以跳上2 级。求该青蛙跳上一个n 级的台阶总共有多少种跳法。
题目分析:

  1. 如下图所示,当只有一阶台阶时,青蛙只有一种跳法。
  2. 当只有两阶台阶时,青蛙有两种算法,也就是一次跳一个或者直接跳两个。
  3. 但当有三阶台阶时,我们此时:
    (1)可以先选择跳1阶,这时第1阶的台阶就看做是新的起点,这时我们可以发现剩2阶台阶了,前面我们说了两阶台阶有两种跳法。
    (2)同样,也可以先选择跳2阶,这时第2阶的台阶就看做是新的起点,这时我们可以发现剩1阶台阶了,前面我们说了1阶台阶有1种跳法。
    (3)所以我们可以得出,当有3阶台阶时,共有2+1种跳法(也就是前面2阶台阶跳法结果 + 前面1阶台阶跳法结果)。
  4. 同理,当有四阶台阶时,我们此时:
    (1)可以先选择跳1阶,这时第1阶的台阶就看做是新的起点,这时我们可以发现剩3阶台阶了,前面我们说了3阶台阶有3种跳法。
    (2)同样,也可以先选择跳2阶,这时第2阶的台阶就看做是新的起点,这时我们可以发现剩2阶台阶了,前面我们说了2阶台阶有2种跳法。
    (3)所以我们可以得出,当有3阶台阶时,共有3+2种跳法(也就是前面3阶台阶跳法结果 + 前面2阶台阶跳法结果)。

在这里插入图片描述
总结: 说白了上面过程其实就是用前面的结果,来快速得到下一步的结果。

分析完题目我们就可以写代码了,实现代码如下所示:
方法一:递归实现

public class test2{
    public static int jump(int n) {
        if(n == 1){
            return 1;
        }else if(n == 2){
            return 2;
        }else{
            return jump(n-1) + jump(n-2);
        }

    }
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        System.out.println(jump(n));
    }
}

import java.util.*;
public class Solution {
    public int jumpFloor (int number) {
        if(number <=1 ){
            return 1;
        }else{
            return jumpFloor(number-1) +jumpFloor(number-2);
        }
    }
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        int a = scanner.nextInt();
        System.out.print(a);
    }
}

优点:代码简单好写。
缺点:慢,会超时,且费空间。
时间复杂度:O(2^n) ,每个递归会调用两个递归,因此呈现2的指数增长。
空间复杂度:O(n) 递归栈的空间,栈空间最大深度为n。
方法二:递归改进实现(用数组或map)
我们会发现方法一中,存在很多重复计算,比较浪费时间,因此为了改进,就把计算过的保存下来。 那么用什么保存呢?一般会想到map或数组。
但这里要说一下,不建议采用数组,因为我们不确定台阶的数量,无法预先申请确定大小的数组。数组实现代码如下所示:

class Solution {
public:
    int f[50]{0};
    int jumpFloor(int number) {
        if (number <= 1) return 1;
        if (f[number] > 0) return f[number];
        return f[number] = (jumpFloor(number-1)+jumpFloor(number-2));
    }
};

public class Solution {
    //设置全局变量,因为实际问题中没有0,则可用0作初始标识值
    private int[] dp = new int[50];
    public int F(int n){
        if(n <= 1)
            return 1;
        //若是dp中有值则不需要重新递归加一次
        if(dp[n] != 0)   
            return dp[n];
        //若是dp中没有值则需要重新递归加一次
        return dp[n] = F(n - 1) + F(n - 2);
    }
    public int jumpFloor(int target) {
        return F(target);
    }
}

时间复杂度:O(n) ,每个数字只算了一次。
空间复杂度:O(n) ,栈空间最大深度。

map实现代码如下所示:

class Solution {
public:
    map<int,int> map_flag;//记录已经被计算出来的值
    int jumpFloor(int number) {
        if(number<=1) return 1;//初始两个台阶的结果
        if(map_flag.count(number)){//已经被计算过;采用count的函数可以降低内存与时间;
            return map_flag[number];
        }
        return  map_flag[number]=jumpFloor(number-1)+jumpFloor(number-2);//未被计算过,存入map;
    }
};

时间复杂度:O(n) ,每个数字只算了一次。
空间复杂度:O(n) ,栈空间最大深度。

方法三:非递归实现(动态规划)
本题既然与斐波那契数列相同,我们就把它放入数组中来解决。

public class test2{
    public static void main(String[] args) {
        int n = 5;
        int[] array = new int[n];
        array[0] = 1;
        array[1] = 2;
        for (int i = 2; i < n; i++) {
            array[i]= array[i-1] + array[i-2];
            System.out.println(i+1+"阶"+array[i]+"种跳法");
        }
    }
}

时间复杂度:O(n) ,遍历了一次长度为n的数组。
空间复杂度:O(n) ,建立了一个数组辅助。

方法四:数组做空间复杂度是o(n),能不能空间复杂度为o(1)呢?(动态规划)
动态规划算法的基本思想是: 将待求解的问题分解成若干个相互联系的子问题,先求解子问题,然后从这些子问题的解得到原问题的解;对于重复出现的子问题,只在第一次遇到的时候对它进行求解,并把答案保存起来,让以后再次遇到时直接引用答案,不必重新求解。动态规划算法将问题的解决方案视为一系列决策的结果。本解法属于动态规划空间优化方法:
继续优化: 发现计算array[4]的时候只用到了array[3]和array[2], 没有用到array[1]和array[0],所以保存array[1]和array[0]是浪费了空间。 只需要设置2个变量定义即可。
在这里插入图片描述
时间复杂度:O(n)、空间复杂度:O(1) ,完美!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值