题目322:
You are given coins of different denominations and a total amount of money amount. Write a function to compute the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return-1
.
Example 1:
coins = [1, 2, 5]
, amount = 11
return 3
(11 = 5 + 5 + 1)
Example 2:
coins = [2]
, amount = 3
return -1
.
Note:
You may assume that you have an infinite number of each kind of coin.
Credits:
Special thanks to @jianchao.li.fighter for adding this problem and creating all test cases.
分析:
class Solution {
public int coinChange(int[] coins, int amount) {
// 典型dp问题,dp三要素:1.边界值。2.状态(这里主动变量是金额,因变量是金额,所以我们外层循环选择金币、内层循环是金额)。3.选择:金额可以放入、不放入
if(coins==null||coins.length==0){
return -1;
}
// dp[i]表示当前金额为i放入的最小硬币数量
int [] dp=new int[amount+1];
// 假设所有最大值都是amount+1,因为金额amount的最多有amount个1元的金币组成,无法由amount+1个组成
Arrays.fill(dp,amount+1);
// 边界值,金额为0的时候没有硬币
dp[0]=0;
for(int i=0;i<coins.length;i++){
for(int j=1;j<=amount;j++){
if(j>=coins[i]){
// 说明当前硬币可以放入,那我们取当前dp[i]和dp[i-coins[i]]+1两者之间最小值作为结果
dp[j]=Math.min(dp[j],dp[j-coins[i]]+1);
}
}
}
// 最后判断返回结果是否为amount+1默认值,如果是则表示无法组成
return dp[amount]==amount+1?-1:dp[amount];
}
}
题目518:
You are given coins of different denominations and a total amount of money. Write a function to compute the number of combinations that make up that amount. You may assume that you have infinite number of each kind of coin.
Note: You can assume that
- 0 <= amount <= 5000
- 1 <= coin <= 5000
- the number of coins is less than 500
- the answer is guaranteed to fit into signed 32-bit integer
Example 1:
Input: amount = 5, coins = [1, 2, 5] Output: 4 Explanation: there are four ways to make up the amount: 5=5 5=2+2+1 5=2+1+1+1 5=1+1+1+1+1
Example 2:
Input: amount = 3, coins = [2] Output: 0 Explanation: the amount of 3 cannot be made up just with coins of 2.
Example 3:
Input: amount = 10, coins = [10] Output: 1
分析:
1.二维数组解法:
class Solution {
public int change(int amount, int[] coins) {
// 思路:典型的dp问题,我们使用二维数组dp[i][j]来表示硬币i个金额j的组合和,那么对于dp的三要素定义:
// 1.边界值 dp[i][0]=1 表示金额为0的情况,我们不放入.dp[0][j]=0表示0个硬币,无论金额为多少,我们都无法放入
// 2.状态:1.金币、金额,因为金币为主动变量,金额为因变量,我们将金币放在最外层循环。金额作为内循环
// 3.选择:1.放入:则dp[i][j]=dp[i-1][j]+dp[i][j-coins[i]],表示不放入+放入的结果
// 2.不放入:dp[i][j]=dp[i-1][j] 表示不放入的话继承dp[i-1][j]的结果
if(coins==null||coins.length==0){
return 0;
}
int n=coins.length;
int [][]dp=new int [n+1][amount+1];
// 边界值
for(int i=0;i<=n;i++){
dp[i][0]=1;
}
// 状态和选择
for(int i=1;i<=n;i++){
for(int j=1;j<=amount;j++){
if(j>=coins[i-1]){
// 可放入
dp[i][j]=dp[i-1][j]+dp[i][j-coins[i-1]];
}else{
// 无法放入
dp[i][j]=dp[i-1][j];
}
}
}
return dp[n][amount];
}
}
2.压缩二维数组(一维数组)解法:
class Solution {
public int change(int amount, int[] coins) {
// 思路:典型的dp组合和问题,dp的三要素:
// 1.边界值 dp[0] 表示金额为0的组合只有一种,那就是都不放入 所以dp[0]=1
// 2.状态:金币、金额,因为金币是主动变量,金额为被动变量,我们将金币放在最外层循环、金额放在内层循环
// 3.选择:1.放入:说明该金币放入可以满足,则dp[i]=dp[i]+dp[i-coins[j]],加上当前dp[i]已有的组合和。2.无法放入,则不用处理
if(coins==null||coins.length==0){
return 0;
}
int [] dp=new int[amount+1];
// 边界值
dp[0]=1;
// 状态和选择
for(int i=0;i<coins.length;i++){
for(int j=1;j<=amount;j++){
if(j>=coins[i]){
// 可放入
dp[j]=dp[j]+dp[j-coins[i]];
}
}
}
return dp[amount];
}
}