【前端er每日算法】动态规划--完全背包问题70/322/279

112 阅读2分钟

题目一 爬楼梯进阶版

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

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

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

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

思路

1个、2个、3个台阶可以重复使用n次,完全背包问题,动态规划四部曲:

  • dp[j]: 爬到n阶的方法数

  • 递推公式: dp[j] += dp[j-i], 是爬1个、2个。。。j-1个台阶的方法数相加

  • 初始化:dp[0] = 1

  • 循环:顺序不同属于不同的方法,是排列问题,要外层循环重量,内层循环物品

var climbStairsm = function(n, m) {
    const dp = new Array(n + 1).fill(0);
    dp[0] = 1;
    for (let j = 1; j <= n; j++) {
        for (let i = 1; i <= m; i++) {
            if (j >= i) {
                dp[j] += dp[j - i];
            }
        }
    }
    return dp[n];
};

climbStairsm(4, 2)

题目二 322. 零钱兑换

给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。

计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。

你可以认为每种硬币的数量是无限的。

思路

每种硬币数量无限:完全背包问题。物品就是硬币,重量是amount,四步曲分析:

  • dp[j]: 凑成amount所需的最少的硬币个数
  • 递推公式: dp[j] = min(dp[j], dp[j - coins[i]]
  • 初始化:dp[0] = 1
  • 循环:最少硬币个数,跟顺序无关, 先遍历物品,再遍历重量
var coinChange = function(coins, amount) {
    const dp = new Array(amount + 1).fill(Number.MAX_VALUE);
    dp[0] = 0;
    const len = coins.length;
    for (let i = 0; i < len; i++) {
        for (let j = coins[i]; j <= amount; j++) {
            dp[j] = Math.min(dp[j], dp[j - coins[i]] + 1);
        }
    }
    if (dp[amount] === Number.MAX_VALUE) {
        return -1;
    }
    return dp[amount];
};

题目三 279. 完全平方数

给你一个整数 n ,返回 和为 n 的完全平方数的最少数量 。

完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。

思路

和上一题基本类似。

  • dp[j]: 返回和为i的完全平方式的最少个数
  • 递推公式: dp[j] = min(dp[j - i * i] + 1, dp[j]]
  • 初始化:dp[0] = 1;
  • 循环顺序:无关顺序,先循环物品,后循环重量
var numSquares = function(n) {
    const dp = new Array(n + 1).fill(Number.MAX_VALUE);
    dp[0] = 0;
    for (let i = 1; i <= n; i++) {
        const value = i * i;
        for (let j = value; j <= n; j++) {
            dp[j] = Math.min(dp[j], dp[j - value] + 1)
        }
    }
    return dp[n];
};