【Leetcode】322. 零钱兑换

52 阅读1分钟

leetcode-322.png

动态规划

解题思路

dp[amount]来记录当前凑成amount最少需要的硬币数量
那么就可以得到一个状态转移方程
用当前这枚硬币(面值为 coin),加上凑出 i - coin 所需的最少硬币数。

dp[0] = 0 // 凑成 0 元需要 0 个硬币
dp[i] = Math.min(dp[i], dp[i-coin])

dp

var coinChange = function (coins, amount) {
    let dp = new Array(amount + 1).fill(Infinity);
    dp[0] = 0;
    for (let i = 0; i <= amount; ++i) {
        for (let coin of coins) {
            if (i >= coin) {
                dp[i] = Math.min(dp[i], dp[i - coin] + 1);
            }
        }
    }
    return dp[amount] === Infinity ? -1 : dp[amount];
};

dfs

  • 定义函数 dfs(remain):表示凑出 remain 元需要的最少硬币数。
  • 递归终止条件:
    • remain < 0:无法凑出,返回 -1
    • remain === 0:正好凑出,返回 0
    • memo[remain] !== -1:之前已经计算过,直接返回缓存结果
  • 对每个硬币 coin,尝试递归调用 dfs(remain - coin),并取最小值。
  • 使用 memo[remain] 缓存结果,避免重复计算。
var coinChange = function (coins, amount) {
    let memo = new Array(amount + 1).fill(-1);
    var dfs = function (remain) {
        if (remain < 0) return -1;
        if (remain === 0) return 0;
        if (memo[remain] !== -1) return memo[remain];
        let min = Infinity;
        for (let coin of coins) {
            const res = dfs(remain - coin);
            if (res >= 0) {
                min = Math.min(min, res + 1);
            }
        }
        memo[remain] = min === Infinity ? -1 : min;
        return memo[remain];
    };
    return dfs(amount);
};