题目描述
【小Q购物】小Q去商场购物,经常会遇到找零的问题。
小Q现在手上有n种不同面值的硬币,每种面值的硬币都有无限多个。
为了方便购物,小Q希望带尽量少的硬币,并且要能组合出1到m之间(包含1和m)的所有面值
输入描述:
第一行包含两个整数m,n(1<=n<=100,1<=m<=10 ),含义如题目所述。
接下来的 n 行,每行一个整数,第 i+1 行的整数表示第 i 种硬币的面值
输出描述:
输出一个整数,表示最少需要携带的硬币数量。如果无解,则输出-1。
备注:
示例1:
输入
20 4
1
2
5
10
输出
5
解答
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int m = scanner.nextInt();
int n = scanner.nextInt();
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = scanner.nextInt();
}
Arrays.sort(arr);
//进行排序后,如果硬币没有为1,则无解。
if (arr[0] != 1) {
System.out.println(-1);
return;
}
/**
* 这里的我思想是根据需要带出门的钱
* 去从大到小去选择硬币是否可以带,
* 比如我需要15元出门,所以10元的硬币,我不能带,
* 因为带了10元硬币,我还剩5元的大小可以带,
* 不满足6-9元的情况,
* 所以从大到小的选择硬币的条件是
* 当前还需带出门的值 减去 硬币的面值*2 大于等于 -1,
* 则可以选择该面值的硬币(比如需要带出门19或者20元,
* 可以选择10元面值的,如果是18元就不能选择10元面值的),
* 每次选择完硬币后需要带出门的钱就减去当前硬币的面值。
* 如果还需要带出门的钱小于第二小的硬币的面值,那就只能用1补齐。
*/
//记录硬币的个数
int count = 0;
//将带出门的钱赋值给sum
int sum = m;
//sum进行循环,直到sum=0,则选择硬币完成
while(sum > 0) {
//如果sum的值小于等于第二小硬币的面值,则只能用1补齐,
//不然不满足条件。面值为1补齐后,就完成选择硬币,跳出循环。
if (1 < n && sum <= arr[1]) {
count += sum;
break;
}
//硬币从大到小选择。
for (int i = n-1; i >= 0; i--) {
//若sum减去当前硬币的面值的两倍大于等于-1,则可以选择该硬币
//原因是:若sum为19或20或者30,则可以选择,
//若为sum为18,选择面值为10的硬币,那么还剩8,
//就不会得到19这种面值的情况,所以不满足。
if (sum - arr[i]*2 >= -1) {
//选择该面值硬币成功后,得到剩余需要匹配的钱。
sum -= arr[i];
count++;
break;
}
}
}
System.out.println(count);
}
}