Leetcode 零钱兑换

在这里插入图片描述

问题描述:

给定不同面值的硬币和一个目标金额 amount,你需要找到组成该金额所需的最少硬币数。如果无法组成该金额,返回 -1。每种硬币可以使用无限次。

算法步骤:

  1. 创建动态规划数组 dp

    • 定义一个数组 dp,其中 dp[i] 表示组成金额 i 需要的最少硬币数。
    • 初始化 dp 数组,长度为 amount + 1,其中每个元素的初始值为 amount + 1(即一个不可能达到的较大值,表示该金额暂时不可达)。
    • 特殊情况:dp[0] = 0,因为组成金额为 0 时,不需要任何硬币。
  2. 动态规划填充 dp 数组

    • 使用两个嵌套循环,外层循环从 1 遍历到 amount,内层循环遍历每个可用的硬币面值。
    • 对于每一个金额 i 和每一个硬币面值 coin,如果当前硬币面值小于或等于 i,则更新 dp[i] 的值为:
      dp[i] = Math.min(dp[i], dp[i - coin] + 1);
      
      • dp[i - coin] + 1 的意思是:如果已经知道用最少的硬币组成金额 i - coin,那么再加上一个当前面值的硬币,即可以组成金额 i,因此可以用 dp[i - coin] + 1 这个值来更新 dp[i]
    • 每次取 dp[i] 的最小值,这样可以确保得到的是最少的硬币数。
  3. 返回结果

    • 最后检查 dp[amount] 的值,如果它仍然是大于 amount 的初始值,说明无法组成该金额,返回 -1;否则返回 dp[amount],即为最少硬币数。

复杂度分析:

  • 时间复杂度O(S * n),其中 S 是目标金额 amountn 是硬币面值的数量。外层循环遍历每个金额,内层循环遍历每个硬币。
  • 空间复杂度O(S),因为我们使用了一个大小为 S + 1 的数组 dp 来存储中间结果。

示例分析:

  • 示例 1

    • 输入:coins = [1, 2, 5], amount = 11
    • 输出:3
    • 解释:可以用 5 + 5 + 1,总共使用 3 枚硬币。
  • 示例 2

    • 输入:coins = [2], amount = 3
    • 输出:-1
    • 解释:无法用面值 2 的硬币凑出金额 3。
  • 示例 3

    • 输入:coins = [1], amount = 0
    • 输出:0
    • 解释:不需要任何硬币。

通过动态规划,该算法高效地解决了每个金额对应的最少硬币数,避免了暴力递归带来的重复计算问题。

java 代码

class Solution {
    public int coinChange(int[] coins, int amount) {
        int[] dp = new int[amount + 1]; //dp[i] 表示凑成数值为i所需的最少硬币数量
        Arrays.fill(dp, amount + 1); //不可能达到 amount + 1,因为硬币最小面额是1
        dp[0] = 0;
        //更新dp数组
        for(int i = 1; i <= amount; ++i) {
            for(int coin : coins) {
                if(coin <= i) {
                    dp[i] = Math.min(dp[i], dp[i - coin] + 1);
                }
            }
        }
        return dp[amount] < (amount + 1) ? dp[amount] : -1;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值