> 文档中心 > 最少的硬币数目问题

最少的硬币数目问题

文章目录

    • 题目
    • 贪心
    • 动态规划
    • 思考

题目

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

贪心

当给定硬币的币值非常正常的时候我们可以使用贪心算法
例如coins = [1, 2, 5,10,20], amount = 56
我们尽可能多的选择面额大的硬币即可

class Solution {public:    int coinChange(vector<int>& coins, int amount) { sort(coins.begin(),coins.end());    int counts=0;  //用来返回结果 for(int i=coins.size()-1;i>=0;i--){ counts+=amount/coins[i]; amount%=coins[i]; if(amount==0){ return counts; } } return -1;    }};

但是当硬币的面值比较古怪,我们就很可能得不到最优解,甚至等不到答案
比如coins = [2,3,5], amount = 9,很明显得不出答案
再比如coins = [1,2,4,5,6], amount = 9 ,用贪心得出6+2+1 ,但实际上只需要4+5

如何判断硬币的面值能否使用贪心呢?
链接一
链接二

动态规划

开一个数组,保存0~amount的最少硬币数目(比如arr[i]保存的就是amount=i时的最少硬币数目)
所以我们要求的就是arr[amount]

递推公式:
arr[amount]=min(arr[amount-coins[0]], arr[amount-coins[1] ],……, arr[amount-coins[coins.size()-1]])+1
还是很好理解的

class Solution {public:    int coinChange(vector<int>& coins, int amount) { int arr[amount+1]; arr[0]=0; for(int i=1;i<amount+1;i++){     int min1=1e9;  for(int j=0;j<coins.size();j++){  if(i>=coins[j]){      min1=min(min1,arr[i-coins[j]]+1);  }     }     arr[i]=min1; } if(arr[amount]==1e9){     return -1; } return arr[amount];    }};

思考

该题每种硬币的数量是无限的,如果当每种硬币的数目都是有限个c1,c2…cn的时候,如何求解?

当硬币面额可以用贪心时,则可以用贪心来求解。
那用动态规划怎么做呢?
参考1
参考2