动态规划解决零钱兑换

132 阅读2分钟

LCR 103. 零钱兑换

中等

题目

给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1

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

 

示例 1:

输入: coins = [1, 2, 5], amount = 11
输出: 3 
解释: 11 = 5 + 5 + 1

示例 2:

输入: coins = [2], amount = 3
输出: -1

示例 3:

输入: coins = [1], amount = 0
输出: 0

示例 4:

输入: coins = [1], amount = 1
输出: 1

示例 5:

输入: coins = [1], amount = 2
输出: 2

 

提示:

  • 1 <= coins.length <= 12
  • 1 <= coins[i] <= 231 - 1
  • 0 <= amount <= 104

给出动态规划的代码方法:

var coinChange = function(coins, amount) {
      const f=[]
      f[0]=0
      for(let i=1;i<=amount;i++){
        //f[i]
        f[i]=Infinity;  //先设置成最大值    
        for(let j=0 ;j<coins.length;j++){
            if(i - coins[j]>=0){
                f[i]=Math.min(f[i],f[i - coins[j]]+1)//我的leetcode函数总结文章有提到这个方法
            }
        }
      }
      if(f[amount]===Infinity){
        return -1
      }
      return f[amount]
};
//循环示例
i=1  f[1]=Math.min(Infinity,1)        f[1]=1
i=2  j=0 f[2]=Math.min(Infinity,2)     f[2]=2
     j=1 f[2]=Math.min(f[2]=2,1)       f[2]=1   f[2]取最小值
i=3  j=0 f[3]=Math.min( Infinity,2)      f[3]=2
i=3  j=1 f[3]=Math.min( f[3]=2,2)   f[3]=  2

这是一个使用动态规划思想解决硬币找零问题的函数,其中:

  • coins 是一个整数数组,表示不同面额的硬币;
  • amount 是需要找零的总钱数。

该函数通过循环遍历 1 到 amount 的范围,对于每个 i,都尝试用所有可用的硬币进行找零。在找零过程中,该函数使用一个数组 f 来记录当前总钱数为 i 时所需的最小硬币数量。

具体实现中,f[i] 初始值设为 Infinity,表示当前还没有任何一种硬币可以组成总钱数为 i。接着,对于每个 j 在硬币数组 coins 中,如果当前总钱数 i 减去硬币面额 coins[j] 的差值大于等于 0,那么就可以考虑把一个面额为 coins[j] 的硬币加入到当前的找零方案中,此时需要用 f[i-coins[j]] 表示从总钱数为 i-coins[j] 的状态转移而来,因为加入了一枚面额为 coins[j] 的硬币。因此,更新 f[i] 的值时,只需要比较 f[i] 和 f[i-coins[j]]+1 两者的大小关系,取其中的较小值即可。

最后,如果 f[amount] 的值仍然为 Infinity,说明无法找零成功,此时函数返回 -1,否则返回 f[amount] 的值,表示总钱数为 amount 时所需的最小硬币数量。

这个算法的时间复杂度为O(amount * coins.length),空间复杂度为O(amount)。