思路:
dp[i]表示 金额 i 的硬币组合的硬币最小数量,dp[i]=min(dp[i-coin[j]+1),coin[j]表示不同硬币面额
难度中等1191
给定不同面额的硬币 coins
和一个总金额 amount
。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1
。
你可以认为每种硬币的数量是无限的。
class Solution {
public int coinChange(int[] coins, int amount) {
int[] dp=new int[amount+1];
dp[0]=0;
Arrays.sort(coins);
for(int i=1;i<=amount;i++){
int j=0;
dp[i]=amount+1; //将当前 i 的硬币组合 dp[i]设为超大值,如果不存在小于 i 的硬币,则dp[i]不会更新,即保持该边界外值(便于 return 时返回-1);另外,后续循环对更大的 i,进行处理时,如果需要用到的之前的 dp 不存在硬币组合,刚好这里的 dp 表示为超大值,一定不会作为 min 值对 dp 进行更新
while(j<coins.length&&coins[j]<=i){
dp[i]=Math.min(dp[i],1+dp[i-coins[j]]);
j++;
}
}
return dp[amount]==amount+1?-1:dp[amount];
}
}
// class Solution {
// public int coinChange(int[] coins, int amount) {
// if(amount==0) return 0;
// int[] dp=new int[amount+1]; //dp[amount]表示 amount 需要的硬币数量
// //可以先给 dp 赋值为amount+1,省去下面的嗯{dp[i-coin]!=0}、{(dp[i]==0}的判断
// for(int coin:coins){
// if(coin<=amount) dp[coin]=1;
// }
// for(int i=2;i<=amount;i++){
// for(int coin:coins){
// if(coin<i&&dp[i-coin]!=0){
// if(dp[i]==0){
// dp[i]=dp[i-coin]+1;
// }else dp[i]=Math.min(dp[i],dp[i-coin]+1);
// }
// }
// /*
// if(dp[i]!=1){
// for(int j=i-1;j>i/2-1;j--){ //不需要这样子拼接,只需要拼上各个钞票面额然后进行比较即可
// if(dp[j]!=0&&dp[i-j]!=0){
// if(dp[i]==0){
// dp[i]=dp[j]+dp[i-j];
// }else dp[i]=Math.min(dp[i],dp[j]+dp[i-j]);
// }
// }
// }
// */
// }
// return dp[amount]==0?-1:dp[amount];
// }
// /*
// public int coinChange(int[] coins, int amount) {
// int max = amount + 1;
// int[] dp = new int[amount + 1];
// Arrays.fill(dp, max);
// dp[0] = 0;
// for (int i = 1; i <= amount; i++) {
// for (int j = 0; j < coins.length; j++) {
// if (coins[j] <= i) {
// dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1);
// }
// }
// }
// return dp[amount] > amount ? -1 : dp[amount];
// }
// */
// }