Too many solutions to coin change maker

299 views Asked by At

The objective of my program is to output all possible change solutions to a given amount of money, for example

DESIRED OUTPUT

Change: 9
[1, 1, 1, 1, 5]
[1, 1, 1, 1, 1, 1, 1, 1, 1]

(with 9 = $0.09) However my output is a little different, my output looks like this

MY OUTPUT

Change: 9
[1, 1, 1, 1, 1, 1, 1, 1, 1]
[1, 1, 1, 1, 5]
[1, 1, 1, 5, 1]
[1, 1, 5, 1, 1]
[1, 5, 1, 1, 1]
[5, 1, 1, 1, 1]

As you can see, it LITERALLY gives me all possible solutions. I only care about the top two answers. It's obvious that this will be a big problem when bigger amounts are asked for. So here's my question: Based off my code, how do I fix it to where it will only display one combination each?

CODE

import java.io.*;
import java.util.*;
import java.lang.*;

public class homework5 {

 public static int change;

   public static void main(String[] args)
     throws FileNotFoundException { //begin main

     ArrayList<Integer> coinTypes = new ArrayList<Integer>();//array to store
                                                             //coin types
     ArrayList<Integer> answerCoins = new ArrayList<Integer>(); //to contain solutions

     Integer i;
     File f = new File (args[0]);
     Scanner input = new Scanner(f); //initialize scanner
       input.nextLine();
       while(input.hasNextInt()) {
           i = input.nextInt();
           coinTypes.add(i); //add all ints to file
       }
        change = coinTypes.get(coinTypes.size()-1);
        coinTypes.remove(coinTypes.size()-1);
            System.out.println("Change: " + change);

    findChange(change, coinTypes, answerCoins);

   }
    private static void findChange(int change, List<Integer> coinTypes,
                            List<Integer> answerCoins) { //contains means of
                                             //finding the change solutions
        if(change == 0) {
           //base case
          System.out.println(answerCoins);
        }
          else if(change < 0) {
           //if negative it can't be a solution
        } else {
          for(int coin = 0; coin < coinTypes.size(); coin++) {

                 answerCoins.add(coinTypes.get(coin)); //choose
                 findChange(change-coinTypes.get(coin), coinTypes, answerCoins);//explore
                 answerCoins.remove(answerCoins.size()-1);    //un-choose
          }

        }

    }

}

Thank you for any and all answers, please try to overlook any other mistakes, I would like to address this question first. Thanks!!

2

There are 2 answers

0
Jason C On BEST ANSWER

A simple approach to this is to avoid creating solutions where the coin you add to the end of the array is of a smaller value than the current end of the array (always add on first iteration when array is empty, of course). That will naturally prune out all of those duplicates. It is easy to implement as it does not involve a significant amount of extra logic beyond just making sure you don't add smaller coins to the end of the array in your search.

It is also very efficient: Your recursion won't even descend into those branches, and you won't have to do any kind of searching for duplicate solutions.

As a bonus side-effect, all of your resulting solutions will contain their coins sorted from smallest to largest. (If instead you avoid adding larger valued coins to the end of the array, your solutions will contain their coins sorted from largest to smallest. Either way, it's a matter of preference.)

2
Min Fu On

You could modify the findChange() to

private static void findChange(int change, List<Integer> coinTypes,
                        List<Integer> answerCoins, int lastcoin);

lastcoin refers to the last coin you add. In the loop, you need not to iterate all coins in coinTypes. Instead, you only iterate the coins smaller or equal than lastcoin descendingly

  for(coin in coins if coin <= lastcoin) { // must in descending order
         answerCoins.add(coinTypes.get(coin)); //choose
         findChange(change-coinTypes.get(coin), coinTypes, answerCoins, coin);//explore
         answerCoins.remove(answerCoins.size()-1);    //un-choose
  }

Then, you will only get [5, 1, 1, 1, 1], and [1, 5, 1, 1, 1] never happens