Search code examples
algorithmrecursioncoin-change

Recursive algorithm to solve change-making problem


I want to make a recursive algorithm that solves the change-making problem. Is it possible to use a non-dynamic approach that not only returns the minimum number of coins but also returns the set of coins used to make-up the given value,

For example, given the value 6 and the set of coins=[1, 3, 4]. Is it possible to make a recursive algorithm that doesn't memoise that can return both the minimum number of coins (2) and the set of coins (3,3)?

EDIT: This is my current algorithm but it only returns the total number of coins:

int makeChangeRecursive(int[] coins, int numCoins, int amount)
   int r, l;
   if (A == 0) return 0;
   else if (n == -1 || A < 0) return -1;
   r = makeChangeRecursive(coins, numCoins - 1, amount);
   l = 1 + makeChangeRecursive(coins, numCoins, amount - coins[numCoins]);
   if (r == -1 && l == 0) return -1;
   else if ((r == -1 || l < r) && l != 0) return l;
   return r;

makeChangeRecursive({1, 2, 5}, 2, 11);

would return 3 but I want it to also provide the set {5, 5, 1}. The second argument (2) is the number of coins minus 1.


Solution

  • Yes it is possible and pretty straightforward.

    You just need to consider the element you return: here an int, to be a struct (int + history) and the function which aggregates your "returned" value: here the sum (1 + int)->int to track the history modification along

    int -> 1 + int
    // becomes
    (int, history) -> (int+1, history + pieceTaken)
    

    Consider the struct

    struct NbCoin {
      int nbCoin;
      vector<int> history; // array of pieces you took during recursion
    }
    
    //now makeChangeRecursive returns the number of coin AND history
    NbCoin makeChangeRecursive(int[] coins, int numCoins, int amount)
        int r, l;
        if (A == 0) return { nbCoin: 0, history: []}; //like before but with the empty history
        else if (n == -1 || A < 0) return { nbCoin: -1, history: []}; // idem
    
        // now contains our history as well
        r = makeChangeRecursive(coins, numCoins - 1, amount);
    
        // here you are taking some coin, so track it into history
        l = makeChangeRecursive(coins, numCoins, amount - coins[numCoins]);
        l = { 
          nbCoin: 1 + l.nbCoin, // like before
          history : l.history.concat(coins[numCoins]) // pieceTaken is coins[numCoins]
          // concat should create a __new__ array merging l.history and coins[numCoins]
        }
    
        // put nbCoin everywhere as our comparison key
        if (r.nbCoin == -1 && l.nbCoin == 0) return { nbCoin: -1, []};
        else if ((r.nbCoin == -1 || l.nbCoin < r.nbCoin) && l.nbCoin != 0) return l;
        return r;
    
    makeChangeRecursive({1, 2, 5}, 2, 11);
    

    Everywhere where you were managing the number of coin, you manage the struct.nbCoin, and you update the history alongside.

    I have not checked whether your algorithm is ok, trusting you.

    The code I modified is now not java valid, up to you to implement!