青蛙跳台阶问题

题目描述

一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n级的台阶总共有多少种跳法。 答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

方法一:递归

假设青蛙跳n阶,不管他们之前怎么跳,最后一跳要么是跳两个台阶,要么就是跳一个台阶。跳到n-1个台阶有f(n-1)种跳法,跳到n-2个台阶有f(n-2)种跳法。那么是不是就有f(n)=f(n-1)+f(n-2),这不就是斐波那契数列嘛。那么我们这道题就尝试用递归来处理

一、传统递归方法

思想:采用分治思想,将一个问题分解成多个子问题,然后求解子问题


时间复杂度:O(2^n):树形结构

空间复杂度:On:当求得一个分支之后,会释放栈帧,然后计算另一个分支的时候再使用栈帧,整体看来仍然是线性的

    public int numWays1(int n) {
        if (n == 1 || n == 0)
            return 1;
        if (n == 2)
            return 2;
        return (numWays1(n - 1) + numWays1(n - 2)) % (1000000007);
    }



分析:这种方法是个整体看来是个“树”,例如n=5。那么f(3)就需要计算2次,如果n更大那么就会出现更多的重复计算,我们能不能用一个容器来记录这些重复出现的数据,这样我们就可以直接使用不用再次计算。

二、递归优化——记忆化递归

思想: 用一个数组来记录到达每个层所需要的步数,递归在这个“树”中会一直向左子树计算,然后回来的过程中每个子树的 孩子的计算都可以用到通过左子树填到数组中的值,那么就避免了很多重复的计算。

时间复杂度:On:在计算一个分支的时候,另一个分支的值已经出来了,就比如当计算f(5)左分支f(4)时,f(4)分支中的f(3)已经被记录到数组中了,那么在计算f(5)的右分支f(3)时,可以直接从数组中拿数据。根据递归特性,那么整体就是线性的

空间复杂度:On:On的数组+数高度h的栈帧Oh,其中h<n。

 public int numWays2(int n) {
        if (n == 1 || n == 0)
            return 1;
        if (n == 2)
            return 2;
        int[] arr = new int[n + 1];
        arr[0] = 1;
        arr[1] = 1;
        arr[2] = 2;
        return myNumWays(n, arr);
    }

    private int myNumWays(int n, int[] arr) {
        if (arr[n] != 0) {//如果数组中已经记录的有值了,那么就直接返回
            return arr[n];
        }
        int ret = (myNumWays(n - 1, arr) + myNumWays(n - 2, arr)) % 1000000007;
        arr[n] = ret;//给该位置赋值
        return ret;
    }

整体分析:其实到这里就有点动态规划的雏形了 那么我们就尝试用动态规划的方式来解决。

方法二:动态规划

动态规划思想:将待求问题分解成多个子问题,但是每个子问题之间又不是完全独立的,是有一定的联系的。和分治最大的区别是,分治思想在求解子问题时,可能会导致大量的重复求解。如果我们可以保存以解决的子问题的结果。再在需要时直接使用以求得的答案。这样我们就可以节省很多资源

public int numWays3(int n) {
        if (n == 0 || n == 1)
            return 1;
        if (n == 2)
            return 2;
        int a = 1, b = 2, num = 3;
        for (int i = 3; i <= n; i++) {
            /*
            算法核心
                将得到的num=a+b,用于记录上一次的结果
                上一轮的b赋值给本轮的a,上一轮的结果赋值给本轮的b。然后再进行计算
             */
            num = (a + b) % (1000000007);
            a = b;
            b = num;
        }
        return num;
    }

时间复杂度:On:循环次数由n控制
空间复杂度:O1 用了三个变量a,b,num
说明:此题我们用num来存储子问题的结果

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值