70. 爬楼梯(完全背包)

70. 爬楼梯

题目链接:70. 爬楼梯(简单)

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

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

示例 1:

输入:n = 2
输出:2
解释:有两种方法可以爬到楼顶。
1. 1 阶 + 1 阶
2. 2 阶

示例 2:

输入:n = 3
输出:3
解释:有三种方法可以爬到楼顶。
1. 1 阶 + 1 阶 + 1 阶
2. 1 阶 + 2 阶
3. 2 阶 + 1 阶

提示:

  • 1 <= n <= 45

解题思路

本题的第一种利用斐波那契的解法在70.爬楼梯中。此处利用完全背包进行另一种解法。

其实,选择”爬1个台阶,爬2个台阶“就相当于选择物品1或物品2,并且物品1和物品2的数量是无限的。如果还可以选择”爬3个台阶,...,爬n个台阶“就相当于选择物品3...物品n。并且该题还属于排列问题,因为”1 阶 + 2 阶“和”2 阶 + 1 阶“是不相同的。

运用动态规划五部曲解决问题:

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

    dp[j]表示有dp[j]种方法爬到有i个台阶的楼顶

  2. 确定递推公式

    将可以选择爬的楼梯数记录在method数组中,即 method= {1,2}。

    于是得到递推公式为:dp[j] = dp[j] + dp[j - method[i]]

  3. dp数组的初始化

    dp[0] = 1

    下标非0的dp[j]初始化为0,这样累计加dp[j - method[i]]的时候才不会影响真正的dp[j]

  4. 确定遍历顺序

    纯完全背包问题中,先遍历物品还是先遍历背包都可以。但本题是是排列问题,即有顺序地进行排列,那就需要先遍历背包 。如果组合问题,并不关心物品使用的顺序,而关心的是物品有没有被用到,所以先遍历物品。

    总结:

    • 如果求组合数就是外层for循环遍历物品,内层for遍历背包。

    • 如果求排列数就是外层for遍历背包,内层for循环遍历物品。

  5. 举例推导dp数组(略)

C++

class Solution {
public:
    int climbStairs(int n) {
        vector<int> dp(n + 1, 0);
        vector<int> method = {1, 2};
        dp[0] = 1;
        for (int j = 0; j <= n; j++) {
            for (int i = 0; i < method.size(); i++) {
                if (j >= method[i]) {
                    dp[j] += dp[j - method[i]];
                }
            }
        }
        return dp[n];
    }
};

JavaScript

/**
 * @param {number} n
 * @return {number}
 */
var climbStairs = function(n) {
    const method = [1, 2];
    const dp = new Array(n + 1).fill(0);
    dp[0] = 1;
    for (let j = 0; j <= n; j++) {
        for (let i = 0; i < method.length; i++) {
            if (j >= method[i]) {
                dp[j] += dp[j - method[i]];
            }
        }
    }
    return dp[n];
};

 

 

posted @ 2022-03-06 16:11  wltree  阅读(64)  评论(0编辑  收藏  举报