剑指 Offer 10- II. 青蛙跳台阶问题

https://leetcode-cn.com/problems/qing-wa-tiao-tai-jie-wen-ti-lcof/

解题思路【 转自:https://leetcode-cn.com/problems/qing-wa-tiao-tai-jie-wen-ti-lcof/solution/jian-zhi-offerer-shua-javacong-di-gui-da-rp2h/  仅做个人备份 浏览请看原文 】

和斐波那契数列问题一模一样

递归法

核心思想:怎么跳到第n阶台阶呢,由于一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶,所以青蛙可以从第n-1阶台阶跳一级来到第n阶,也可以第n-2阶台阶跳两级来到第n阶台阶。同样的,第n-1和第n-2也满足这个条件,本质就是递归问题。既然是递归就可以用树形结构表示。

以n=6为例

10(2)-1.png

解题代码(超时)

class Solution {
    public int numWays(int n) {
        return Ways(n);
    }
    private int Ways(int n){
        if(n <= 1){
            return 1;
        }
        if( n == 2){
            return 2;
        }
        return (Ways(n-1) % 1000000007) + (Ways(n-2) % 1000000007);
    }
}

备忘录法

我们观察递归树,可以看到其实递归过程中我们做了很多重复性的工作

10(2)-2.png

图中颜色相同的部分就是重复性的工作,所以为了缩短时间我们就需要避免重复性的工作。

减少重复的工作的方法就是将已经计算过的数值保存起来

这就是备忘录的核心工作,本质就是空间换时间

class Solution {
    public int numWays(int n) {
        int[] memo = new int[101];
        // 备忘录初始化
        memo[0] = 1;
        memo[1] = 1;
        memo[2] = 2;
        return Ways(memo, n);
    }
    private int Ways(int[] memo, int n){
        // 如果备忘录中已经存在值,直接返回已经记录的值
        if(memo[n] !=0){
            return memo[n];
        }
        memo[n] = (Ways(memo, n-1) + Ways(memo, n-2)) % 1000000007;
        return memo[n];
        
    }
}

动态规划

很明显,青蛙跳台阶的问题就是斐波那契数列问题

状态定义: 设 dpdp 为一维数组,其中 dp[i] 就是青蛙跳上一个 n 级的台阶总共跳法数
转移方程: dp[i + 1] = dp[i] + dp[i - 1] ,即对应数列定义 f(n + 1) = f(n) + f(n - 1) ;
初始状态: dp[0] = 1dp[0]=1, dp[1] = 1dp[1]=1 ,即初始化前三个数字;
返回值: dp[n] ,青蛙跳上一个 n 级的台阶跳法数
时间复杂度O(n),空间复杂度O(n)

解题代码

public class Solution {
    public int numWays(int n) {
        if (n == 0 || n == 1) {
            return 1;
        }
        // 初始状态
        int[] dp = new int[n + 1];
        dp[1] = 1;
        dp[2] = 2;
        // 状态转移
        for (int i = 3; i <= n; i++) {
            dp[i] = (dp[i - 2] + dp[i - 1]) % 1000_000_007;
        }
        return dp[n];
    }
}

动态规划的优化

其实很久状态转移方程我们也可以很清楚的看出来,dp[n]只跟前两项即dp[n-1], dp[n-2]有关,既然如此那么我们就不需要申请那么多空间,直接用两个变量来表示前两项就可以了。

时间复杂度O(n),空间复杂度O(1)

解题代码

public class Solution {
    public int numWays(int n) {
        if (n == 0 || n == 1) {
            return 1;
        }
        // 两个变量表示前两项
        int pre = 1, cur = 2;
        for (int i = 3; i <= n; i++) {
            int tmp = (pre + cur) % 1000_000_007;
            // 更新变量,以便继续求解
            pre = cur;
            cur = tmp;
        }
        return cur;
    }
}
func numWays(n int) int {
    if n <= 1 {
        return 1
    }
    per, cur := 1, 2
    for i := 3; i <= n; i++ {
        tmp := (per + cur) % 1000_000_007
        per = cur
        cur = tmp
    }
    return cur
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值