Inspired by a leetcode exercise, I wrote my own coin changer:
You are given an integer array coins representing coins of different denominations and an integer amount representing a total amount of money.
Return 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.
You may assume that you have an infinite number of each kind of coin.
Example:
Input: coins = [1,2,5], amount = 11
Output: 3
Explanation: 11 = 5 + 5 + 1
CoinType
public class CoinType implements Comparable<CoinType>{
private final int value;
public CoinType(int value){
this.value = value;
}
public int getValue() {
return value;
}
@Override
public String toString() {
return "value = "+value;
}
@Override
public int compareTo(CoinType o) {
return -1 * Integer.compare(value, o.getValue()); //biggest first!
}
}
CoinTypes
public class CoinTypes {
private List<CoinType> coinTypes = new ArrayList<>();
public CoinTypes(int[] samples) {
coinTypes = new ArrayList<>(Arrays.stream(samples).mapToObj(CoinType::new).toList());
Collections.sort(coinTypes);
}
public List<CoinType> getCoinTypes() {
return coinTypes;
}
}
Change (returned money, my bad english, sorry)
public class Change {
private Map<CoinType, Integer> change = new HashMap<>();
private int amount;
public Change(int amount) {
this.amount = amount;
}
public int getRemaining() {
int sum = change.entrySet().stream().mapToInt(Change::multiply).sum();
return amount - sum;
}
public static int multiply(Map.Entry<CoinType, Integer> entrySet){
return entrySet.getKey().getValue() * entrySet.getValue();
}
public void add(CoinType coinType, int amount) {
change.put(coinType, amount);
}
@Override
public String toString() {
return change.entrySet().stream().map(e -> ""+e.getValue()+" coins of "+e.getKey()).collect(Collectors.joining(","));
}
public int getAmountCoins() {
return change.values().stream().mapToInt(i -> i).sum();
}
public boolean hasRemaining() {
return getRemaining() != 0;
}
}
CoinChanger
public class CoinChanger {
private final CoinTypes coinTypes;
public CoinChanger(int[] coinTypes) {
this.coinTypes = new CoinTypes(coinTypes);
}
public Change change(int result) {
Change change = new Change(result);
for(CoinType coinType: coinTypes.getCoinTypes()){
int amount = change.getRemaining() / coinType.getValue();
change.add(coinType, amount);
}
if(change.hasRemaining()){
throw new IllegalArgumentException("cannot change to that amount with my coinTypes");
}
return change;
}
}
App running example
public class App{
public static void main(String[] args) {
int[] coins = {1,2,5};
int amount = 11;
CoinChanger coinChanger = new CoinChanger(coins);
try {
Change change = coinChanger.change(amount);
System.out.println(change);
}catch (IllegalArgumentException e){
System.out.println("cannot give change: "+e);
}
}
}