4

I am trying to use recursion to find the minimum amount of coins to make a given amount. I have code that is able to list the minimum amount of coins required, but I can't seem to find a way to print off which coins were used to come up with the solution. I've searched and found similar examples, but I can't seem to properly apply it to this.

Here is what I have thus far:

import java.util.*;

public class Coins{

    public static int findMinCoins(int[] currency, int amount) {
        int i, j, min, tempSolution;

        min = amount;

        for (i = 0; i < currency.length; i++) {
            if (currency[i] == amount) {
                return 1;
            }
        }

        for (j = 1; j <= (amount / 2); j++) {
            tempSolution = findMinCoins(currency, j) + findMinCoins(currency, amount - j);
            if (tempSolution < min) {
                min = tempSolution;
            }
        }
        return min;
    }

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int[] USA =
        {1, 5, 10, 25, 50};
        System.out.println("Please enter an integer amount.");
        int amount = in.nextInt();
        int minCoins = findMinCoins(USA, amount);
        System.out.println("The minimum number of coins to make " + amount + " in United States currency is " + minCoins + ".");
        System.out.println("The coins used were:");
        /*Print coins used to find minCoins.*/
        in.close();
    }
}

An example of the code running thus far:

Please enter an integer amount.
17
The minimum number of coins to make 17 in United States currency is 4.
The coins used were:

If someone could give me some insight on how to do this, it would be much appreciated.

Riddhesh Sanghvi
  • 1,218
  • 1
  • 12
  • 22
Sigonious
  • 43
  • 1
  • 5
  • What is the available coins ? also, try to describe how it should work - the current code runs forever for some inputs ( ie - 44 for example ) – chenchuk Oct 18 '15 at 19:47
  • Side note on quality: please consider the naming in your source code. It is terrible. First of all, there are conventions; for example class names start Uppercase. Then: a name should say what the thing it names is about. So, number is a number, and value a value ... huh? For the actual problem, you might want to start using printlns here and there ... just to print intermediate results; that might give you a clue ... where and how to add the relevant printouts. – GhostCat Oct 18 '15 at 19:47
  • @chenchuk The available coins can be any set of integers. For the code I posted, I just used {1,5,10,25,50}. As for the result, it prints out the string "The minimum number of coins to make 17 in United States currency is 4." if 17 is entered. I'm not sure how to improve the runtime with higher values without using Dynamic Programming. – Sigonious Oct 18 '15 at 19:55
  • @Jägermeister Alright, I fixed some of the quality issues in my edit, if you see any others, please don't hesitate to correct me as I am trying to make my code more legible. As for adding printlns, I tried making an list to store each value of currency[i] in the first for loop but I made no progress there. Apart from that, I've spent time debugging line by line, but I am still lost on where to start. – Sigonious Oct 18 '15 at 20:14
  • @Sigonious you don't need to use recursion, see my answer below. It has tests proving it works. – ESala Oct 18 '15 at 21:03

5 Answers5

2

I think this should totally work with what you want to achieve. Just call the public static int findMinCoins(arg1, arg2) and it will output you the minimum number of coins and all the particular coins(It will show times the number of its occurrence) used using recursive algorithms.

public static int findMinCoins(int[] currency, int amount) {
    int min = findMinCoins(currency, amount, 0);
    System.out.print("The coins used were: ");
    return min;
}
private static int findMinCoins(int[] currency, int amount, int min){
    int number, value1, value2;
    int min1 = min;
    for(int i=currency.length-1; i>=0; i--) {
        if (amount>=currency[i]){
            amount = amount - currency[i];
            System.out.print(currency[i] + " ");
            min1 = findMinCoins(currency, amount, min1);
            return ++min1;
        }
    }
    return min1;
}
burglarhobbit
  • 1,860
  • 2
  • 17
  • 32
  • This will not work if the size of the currency array changes. – ESala Oct 18 '15 at 20:38
  • I would have got serious wrist pain if I would have written these ifs with the indexes. – Gábor Lipták Oct 18 '15 at 20:44
  • @Darkean Updated! This answer's the OP's question. – burglarhobbit Oct 18 '15 at 20:55
  • @Mr.Robot see my answer, no need for recursion. – ESala Oct 18 '15 at 20:56
  • 2
    @GáborLipták Now please pain your wrist a little more to remove the downvote and provide my answer some positive feedback please! – burglarhobbit Oct 18 '15 at 20:56
  • @Darkean Wait a second, OP wanted to do this using recursion. That's why my answer is in recursive form. It can be done without it all the way. – burglarhobbit Oct 18 '15 at 20:58
  • @Mr.Robot this is the output format I am looking for, however it uses the cheat method. So given a list of currencies {1,2,3,5,7,11,13} and an amount of 22, the result comes out to 3 coins, 13 7 2, as opposed to 2 coins, 11 11. Thank you for your answer though. I appreciate anyone's help. – Sigonious Oct 18 '15 at 23:41
  • 1
    @Mr.Robot I did not make any downvote. I did not meant it offending, sorry. I just wanted to express in a funny way, that this kind of repeated code must cause bad conscience for us developers. Sorry again if I was offending. – Gábor Lipták Oct 19 '15 at 09:26
  • 1
    @Mr.Robot as a positive feedback: The code above is a lot nicer as was before. Maybe giving back a list of coins would be a better solution, since the list.size() would deliver the number of coins and the items of the list could "explain" the solution. This particular case probably choosing a recursive solution is not the best, since entering a bigger amount of money can easily cause a stackoverflow. Probably a linear solution is better. Still your effort for providing a solution is appretiated. – Gábor Lipták Oct 19 '15 at 09:31
  • 1
    @GáborLipták Thank you for your feedback. Yes the recursive part could cause a stackoverflow and the linear solution is still better though. To provide a list of coins, don't you think printing out the coin value when it matches as I have in the answer would meet the requirements? – burglarhobbit Oct 19 '15 at 13:53
  • @Mr.Robot : usually it is a good practice to 1. provide as much information as possible (so not only number of coins but also the list) and 2. separate the presentation (system outs) from the business logic (calculation). The requirements are defined by Sigonious, so ask him :) – Gábor Lipták Oct 19 '15 at 18:46
0

Here you go, you have a test and the function is below. Notice that edge cases are not handled, such as empty currency or negative amount.

It is assumed that the currency array is sorted. If not, sort it with Arrays.sort(currency).

public class FindMinimumCoinsTest {

  @Test
  public void test() throws Exception {
      int[] USA = { 1, 5, 10, 25, 50 };
      assertEquals(2, findMinCoins(USA, 11));
      assertEquals(4, findMinCoins(USA, 8));
      assertEquals(4, findMinCoins(USA, 111));
      assertEquals(3, findMinCoins(USA, 27));
  }

  public static int findMinCoins(int[] currency, int amount) {
      int coins = 0;
      int sum = 0;
      int value, n;

      for (int i = currency.length - 1; i >= 0; i--) {
          value = currency[i];
          n = (amount - sum) / value;
          if (n > 0) {
              coins += n;
              sum += n * value;
          }
      }
      return coins;
    }
}

Also, no need for recursion using this method ;)

ESala
  • 6,878
  • 4
  • 34
  • 55
  • Thank you for your answer, but one requirement of this program is that it uses recursion to find the solution. I was able to find a Dynamic Programming solution, but can't seem to figure out a way to print both the minimum coins and which coins were used to find that minimum using recursion. – Sigonious Oct 18 '15 at 23:46
0

Here is a recursive code (working, but need a fix ...). The idea is to pass and array with all coins {1,5,10,25,50} and recursively call from left to right (until end of array)

NOTES :

There is a little bug in the output

The number is passed as array of 1 element instead of a primitive int. (this is to have a reference type to keep its value through all recursive calls :

public class coins {

    public static void main(String[] args) {
        // arrays of coin types
        int[] coinTypes = { 0, 1, 5, 10, 25, 50 };
        // arrays are references, so changing them
        // inside the recursive function will 'really' change
        int[] price = {11}; // sample input
        tryBigger(price, coinTypes, 0);
    }

    // tries to see if higher coin is possible by passing array
    // of coin types and recursively call until the end of array
    public static void tryBigger(int[] price, int[] theCoins, int index) {
        if (index < theCoins.length-1){
            // until last element
            if (price[0] > theCoins[index]){
                tryBigger(price, theCoins, ++index);
            }
        }
        // find amount of this coin
        int thisCoin = price[0]/theCoins[index];
        // remove the amount already got before
        price[0] = price[0] - thisCoin*theCoins[index];
        System.out.println(thisCoin + " coins of " + theCoins[index]);
        return;

    }
}
chenchuk
  • 5,324
  • 4
  • 34
  • 41
  • This output format is what I'm looking for, but I believe this uses the "cheat" method of solving it. For example, if you use a currency set of {1,2,3,5,7,11,13} and change price to 22, you are given the result of a coin of 13, 7, and 2 instead of two 11 coins. Thank you for your answer all the same. – Sigonious Oct 18 '15 at 23:36
  • This is a BIG difference in the algorithm. my algorithm try to have the biggest possible coins, yours have the least number of coins ( of any type ) - is that what you mean ? – chenchuk Oct 19 '15 at 04:22
0

In the code you offer, either the number 1 or min are returned by the recursive function. Keeping with this method, one way you could obtain the list of coins is by altering the return variable to include both coins and count.

Here's an example of the general idea; since I don't know about programming in Java, I'll leave the implementation to you.

if (currency[i] == amount){
    return [1,i];

...

temp1 = findMinCoins(currency,j);
temp2 = findMinCoins(currency,amount - j);

if(temp1[0] + temp2[0] < min[0]){
    min = [temp1[0] + temp2[0]] concatenated with temp1[1..] and temp2[1..]
גלעד ברקן
  • 23,602
  • 3
  • 25
  • 61
0

I was working on something similar and this is what I came up with. You can hold the used coins in a separate array and have a helper function print the last used coins recursively. If you want to return a list or a string you can just have the helper create and return one.

/**
* FIND MINIMAL NUMBER OF COINS TO MAKE CHANGE, WITH CHANGE VALUES: 1, 2, 5, 10, 20, 50, 100, 200
*
* @param change The amount of change we need to give
* @return Minimal amount of coins used
*/
public static int minimalNumberOfCoinsToMakeChange(int change) {
    int[] denominations = {1, 2, 5, 10, 20, 50, 100, 200};
    int[] dp = new int[change + 1];
    int[] origins = new int[change+1];
    dp[0] = 0;
    for (int i = 1; i <= change; i++) {
        dp[i] = Integer.MAX_VALUE;
        for (int coin : denominations) {
            if (i - coin < 0) {
                continue;
            }
            dp[i] = Math.min(dp[i], 1 + dp[i - coin]);
            origins[i] = coin;
        }
    }
    if (dp[change] == Integer.MAX_VALUE) {
        return -1;
    }
    printPath(origins);
    return dp[change];
}

/**
 * HELPER FUNCTION - GET PATH
 *
 * @param origins Array with origins from main function
 */
private static void printPath(int[] origins) {
    int last = origins[origins.length-1];
    System.out.println(last);
    origins = Arrays.copyOfRange(origins,0,origins.length-last);
    if (origins.length-1 > 0){
        printPath(origins);
    }
}

I hardcoded the array of denominations in this example, but you should be able to remove it and pass another as argument. It is not the most efficient way, but might be helpful to people who are only just getting into dynamic programming, like I am. Cheers!

H3AR7B3A7
  • 4,366
  • 2
  • 14
  • 37