爬楼梯(背包角度解决)

题干分析

力扣入口

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

注意:给定 n 是一个正整数。

示例 1: 输入: 2 输出: 2 解释: 有两种方法可以爬到楼顶。

  • 1 阶 + 1 阶
  • 2 阶

示例 2: 输入: 3 输出: 3 解释: 有三种方法可以爬到楼顶。

  • 1 阶 + 1 阶 + 1 阶
  • 1 阶 + 2 阶
  • 2 阶 + 1 阶

解题思路

之前讲这道题目的时候,因为还没有讲背包问题,所以就只是讲了一下爬楼梯最直接的动规方法(斐波那契)。

这道题目 我们在动态规划:爬楼梯 中已经讲过一次了,原题其实是一道简单动规的题目。

既然这么简单为什么还要讲呢,其实本题稍加改动就是一道面试好题。

改为:一步一个台阶,两个台阶,三个台阶,…,直到 m个台阶。问有多少种不同的方法可以爬到楼顶呢?

1阶,2阶,… m阶就是物品,楼顶就是背包。

每一阶可以重复使用,例如跳了1阶,还可以继续跳1阶。

问跳到楼顶有几种方法其实就是问装满背包有几种方法。

此时大家应该发现这就是一个完全背包问题了!

和题目动态规划:377. 组合总和 Ⅳ 本就是一道题了。

动规五部曲分析如下:

1. 确定dp数组以及下标的含义

dp[i]:爬到有i个台阶的楼顶,有dp[i]种方法。

2. 确定递推公式

动态规划:494.目标和动态规划:518.零钱兑换II动态规划:377. 组合总和 Ⅳ中我们都讲过了,求装满背包有几种方法,递推公式一般都是dp[i] += dp[i - nums[j]];

本题呢,dp[i]有几种来源,dp[i - 1],dp[i - 2],dp[i - 3] 等等,即:dp[i - j]

那么递推公式为:dp[i] += dp[i - j]

3. dp数组如何初始化

既然递归公式是 dp[i] += dp[i - j],那么dp[0] 一定为1,dp[0]是递归中一切数值的基础所在,如果dp[0]是0的话,其他数值都是0了。

下标非0的dp[i]初始化为0,因为dp[i]是靠dp[i-j]累计上来的,dp[i]本身为0这样才不会影响结果。

4. 确定遍历顺序

这是背包里求排列问题,即:1、2 步 和 2、1 步都是上三个台阶,但是这两种方法不一样

所以需将target放在外循环,将nums放在内循环。

每一步可以走多次,这是完全背包,内循环需要从前向后遍历。

5. 举例来推导dp数组

介于本题和动态规划:377. 组合总和 Ⅳ 几乎是一样的,这里我就不再重复举例了。

总结

本题看起来是一道简单题目,稍稍进阶一下其实就是一个完全背包!

面试考点

  1. 先出一个本题原题,看其表现,如果顺利写出来,进而在要求每次可以爬[1 - m]个台阶应该怎么写。
  2. 再考察一下两个for循环的嵌套顺序,为什么target放外面,nums放里面。

代码实现

class Solution {
   // 70.爬楼梯(背包角度解决)
    public int climbStairs(int n){
        int[] dp = new int[n + 1];
        int m = 2; // 有两个物品: item1重量为1,item2重量为2
        dp[0] = 1;

        for(int i = 1; i <= n; i++){ // 遍历背包
            for(int j = 1; j <= m;j++) { // 遍历物品
                if(i >= j) // 当前的背包容量大于物品重量的时候,我们才需要记住当前的这个装的方法(方法数+)
                    dp[i] += dp[i - j];
            }
        }
        return dp[n];
    }
}

参考资料代码随想录-70. 爬楼梯

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值