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

本文详细解析了青蛙跳台阶问题的解决方法,通过递归、带备忘录的递归及动态规划三种方式来求解,并针对动态规划进行了空间优化。

题目来源

leetcode 剑指 Offer

分析

有 n 个台阶,设 n 个台阶有 dp[n] 种跳法,分情况:

  1. 青蛙跳 1 个台阶,剩下的 n-1 个台阶有 dp[n-1] 种跳法;
  2. 青蛙跳 2 个台阶,剩下的 n-2 个台阶有 dp[n-2] 种跳法。

由上找到状态之间的关系:

dp[n] = d[n-1] + dp[n-2]
一直按照这种状态转移下去,直到基准 dp[0]=1、dp[1]=1。

解法

1)按照上述形式,可以使用递归,即求 dp[n] 就是求 dp[n-1]、dp[n-2]。这里不展示代码了。

2)进一步分析,如 dp[5]=dp[3]+dp[4]、dp[4]=dp[3]+dp[2] …。可以看出,原问题分解为子问题时,出现子问题重复计算。我们可想着用一个变量保存以计算过的子问题,于是可以采用带有备忘录的递归算法。(代码略)。

3)该问题其实符合动态规划的问题,所以可以采用动态规划,使用 dp table。使用动态规划与带备忘录的递归算法从时间以及空间复杂度上是相等的。但是可以对动态规划的空间复杂度进行优化,使其为 O(1)。

优化思路:当前状态值是最近的两个状态值的和,与其他历史值无关,所以每次只要迭代记录邻近两个状态值即可。为什么带备忘录的递归算法不能这样优化,因为递归是函数调用函数,类似深度优先搜索原则,只有子问题 dp[n-1] 计算完结果才会执行子问题 dp[n-2] 计算结果。如果不记录子问题 dp[n-1] 中的多个中间值,子问题 dp[n-2] 就会重复计算。

代码如下:

class Solution {
    public int numWays(int n) {
        // 动态规划优化
        if(n<=1){
            return 1;
        }
        // 使用两个单变量代替状态数组。
        int pre = 1;
        int next = 1;
        int res = 0; 
        for(int i=2; i<=n; i++){
            res = (pre + next) % 1000_000_007 ;
            pre = next;
            next = res;
        }
        return res;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值