LeetCode 322. 零钱兑换,动态规划详细解法

322. 零钱兑换

题目来源

322. 零钱兑换

题目分析

给定一个硬币面额数组 coins 和一个总金额 amount,我们需要计算凑成该总金额所需的最少硬币个数。如果无法凑成该金额,则返回 -1

题目难度

  • 难度:中等

题目标签

  • 标签:数组、动态规划

题目限制

  • 1 <= coins.length <= 12
  • 1 <= coins[i] <= 5000

解题思路

这道题可以使用动态规划来解决,是一个典型的完全背包问题:

  1. 问题定义:设 dp[i] 为凑成金额 i 所需的最少硬币个数,目标是求出 dp[amount]

  2. 状态转移:对于每个硬币面额 coin,如果我们选择使用该硬币,则 dp[i] = dp[i - coin] + 1。我们需要在所有可能的选择中取最小值,即 dp[i] = min(dp[i], dp[i - coin] + 1)

  3. 初始化

    • 初始化 dp[0] = 0,表示凑成金额 0 所需的硬币个数为 0
    • 初始化 dp[i] = amount + 1 表示初始状态下无法凑成金额 i
  4. 边界条件

    • 如果 dp[amount] 仍然等于 amount + 1,说明无法凑成该金额,返回 -1
    • 否则,返回 dp[amount]

核心算法步骤

  1. 初始化

    • 定义 dp 数组,长度为 amount + 1,初始化为 amount + 1,表示无法凑成该金额。
  2. 状态转移

    • 对于每个 coin,遍历从 coinamount 的所有金额,更新 dp 数组。
  3. 输出结果

    • 返回 dp[amount],如果 dp[amount] 等于 amount + 1,则返回 -1,否则返回 dp[amount]

代码实现

以下是求解零钱兑换问题的 Java 代码:

/**
 * 322. 零钱兑换
 * @param coins  硬币面额数组
 * @param amount 总金额
 * @return 凑成总金额所需的最少的硬币个数
 */
public int coinChange(int[] coins, int amount) {
    int[] dp = new int[amount + 1];
    for (int i = 1; i <= amount; i++) {
        dp[i] = amount + 1;
    }

    for (int coin : coins) {
        for (int j = coin; j <= amount; j++) {
            dp[j] = Math.min(dp[j], dp[j - coin] + 1);
        }
    }
    return dp[amount] == amount + 1 ? -1 : dp[amount];
}

代码解读

  • coinChange 方法
    • 初始化 dp 数组,dp[i] 表示凑成金额 i 所需的最少硬币个数,初始状态下设为 amount + 1 表示不可达。
    • 外层循环遍历每个 coin,内层循环更新 dp 数组,尝试通过当前 coin 凑成不同的金额。

性能分析

  • 时间复杂度O(n * amount),其中 ncoins 数组的长度,amount 是目标金额。
  • 空间复杂度O(amount),因为我们只需要一个长度为 amount + 1 的数组 dp

测试用例

你可以使用以下测试用例来验证代码的正确性:

int[] coins1 = {1, 2, 5};
int amount1 = 11;
int result1 = coinChange(coins1, amount1);
System.out.println(result1);
// 输出: 3 (11 = 5 + 5 + 1)

int[] coins2 = {2};
int amount2 = 3;
int result2 = coinChange(coins2, amount2);
System.out.println(result2);
// 输出: -1 (无法凑成3)

int[] coins3 = {1};
int amount3 = 0;
int result3 = coinChange(coins3, amount3);
System.out.println(result3);
// 输出: 0 (无需任何硬币即可凑成0)

扩展讨论

其他实现

  • BFS
    • 也可以使用广度优先搜索 (BFS) 来解决零钱兑换问题,从 amount 开始不断减去 coins 中的值,直到凑成 0 或无解。

总结

通过动态规划的思想,我们能够高效地解决零钱兑换问题。通过合理定义 dp 数组的含义,状态转移方程,以及对初始状态的处理,可以解决类似的完全背包问题。


  • 8
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值