问题:
分硬币问题,假设sum代表总的钱数,数组a中的元素代表有的单个硬币,问sum最少需要a中的几个硬币(可以重复)加起来才能得到sum?
比如:
int[] a = {1,10,15,21,25};
int sum = 63;
那么最少就是3个21的才能得到sum
ps:贪婪算法在这个例子中就不成立,所以贪婪方法没有用
算法1:
和大整数分割成 多个小整数问题(一)一样,循环每次sum减去a中的有的一个硬币面值,总数就等于这个硬币数(1)+剩下的需要的最小硬币数硬币数,循环每次结果都和最小比较如果更少就更新最小值,边界条件是如果等于0就表明这个构成方法有效,返回0;如果小于0则无效,返回
Integer.MIN_VALUE
最后result为负则不更新最小硬币数值
代码:
public int minCoinNumbers1(int[] a,int sum){
int result = 0;
int min = Integer.MAX_VALUE;
if(sum<0)//小于0就是硬币没有组合成功,返回一个极大负值通过result>0不影响结果判断
return Integer.MIN_VALUE;
if(sum==0)//等于0就是硬币一个组合成功,返回0结
// 束一个递归过程,前面每次递归加的1就是硬币数
return 0;
for(int i=0;i<a.length;i++){
result = 1+minCoinNumbers1(a,sum-a[i]);
if(result>0&&result<min){
min = result;
}
result = 0;
}
return min;
}
算法2:weiss书中的代码,缺陷就是默认硬币面值为1存在,如果数组a中1不存在算法就会出现问题.
思路是:硬币数等于:
for(int i=1;i<=sum/2;i++){//循环从1开始,从0开始就是sum由0+sum组成的无穷递归
result = minCoinNumbers2(a,i)+minCoinNumbers2(a,sum-i);
}
这个循环中的最小值。
边界条件是:如果在a数组中存在对应的sum,那就直接返回1表示取这个硬币。
代码如下:
public int minCoinNumbers2(int[] a,int sum){
int result = 0;
int min = Integer.MAX_VALUE;
for(int i=0;i<a.length;i++){
if(sum==a[i]){
return 1;
}
}
for(int i=1;i<=sum/2;i++){//循环从1开始,从0开始就是sum由0+sum组成的无穷递归
result = minCoinNumbers2(a,i)+minCoinNumbers2(a,sum-i);
if(min>result){
min = result;
}
result = 0;
}
return min;
}