题目:
给定不同面额的硬币(coins)和一个总金额(amount)。写一个函数来计算可以
凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合方式能组成总金额,返回-1。
示例 1:
coins = [1, 2, 5], amount = 11
return 3 (11 = 5 + 5 + 1)
示例 2:
coins = [2], amount = 3
return -1.
注意:你可以认为每种硬币的数量是无限的。
思路:
这个问题个0-1背包问题类似,区别在于每种硬币可以重复使用;做法是从最小的硬币开始,去构成目标解,直到得到的解大于目标解,就使用下一个硬币组合构成。
class Solution {
private static int maxValue = 100000000;
public int search(int index, int amount, int[] coins){
if(index >= coins.length){
return maxValue;
}
if(amount == 0){
return 0;
}
if(amount < 0){
return maxValue;
}
return Math.min(search(index, amount - coins[index], coins) + 1,
search(index + 1, amount, coins));
}
public int coinChange(int[] coins, int amount) {
int val = search(0, amount, coins);
if(val < maxValue){
return val;
}else{
return -1;
}
}
}
动态规划:将计算结果保存在特定结构里,这种结构可能是(一维数组、二维数组、三维数组或者Map),将原始问题分解成子问题,先求子问题,从这些子问题的解得到原始问题的解。
class Solution {
private static int[][] result;
private static int maxValue = 100000000;
public int search(int index, int amount, int[] coins){
if(index >= coins.length){
return maxValue;
}
if(amount == 0){
return 0;
}
if(amount < 0){
return maxValue;
}
if(result[index][amount] >= 0){
return result[index][amount];
}
result[index][amount] = Math.min(search(index, amount - coins[index], coins) + 1,
search(index + 1, amount, coins));
return result[index][amount];
}
public int coinChange(int[] coins, int amount) {
result = new int[20][10000];
for(int i = 0;i < 20; i++){
for(int j = 0; j < 10000; j++){
result[i][j] = -1;
}
}
int val = search(0, amount, coins);
if(val < maxValue){
return val;
}else{
return -1;
}
}
}