Subset Sum: Coin Exact Change
by Isai Damier, Android Engineer @ Google

/*********************************************************************
 * Author: Isai Damier
 * Title: Subset Sum of Coins for Exact Change
 * Project: geekviewpoint
 * Package: algorithms
 *
 * Statement:
 *   Given a set of coins, find the shortest sequence of coins that
 *   adds up to a given total t.
 *
 * Time Complexity: O(n*t)
 *    where n is the number of coins and t is the total to make change for.
 * 
 * Sample Input: coin={1,5,10,25}; t=167
 * Sample Output: [1, 1, 5, 10, 25, 25, 25, 25, 25, 25]
 * 
 * Dynamic Programming Strategy:
 * 
 *   Our approach is to compute the number of coins in each subtotal
 *   amount of money from 0 to t, inclusive. The technique is to
 *   add coins to a previously found subtotal so to get the next
 *   subtotal, until we solve for the minimum number of coins in t.
 *   After that, we simply walk the list of subtotals to get the
 *   exact change (you'll see).
 * 
 * 0] Create an array N of size t+1: 
 *     The indices/keys of the array represent different subtotals.
 *     And the element/value at each index represents the number of
 *     coins that adds up to that given subtotal:
 *     N[subtotal] = number of coins
 * 1] Initialize N to infinity:
 *     Before any computation is performed, assume/pretend that each
 *     subtotal takes an infinite number of coins to compute. We know
 *     that's not true, but that's what we have to prove.
 * 2] Set N at index 0 to 0:
 *     Recall that for the N array, each index represents a subtotal
 *     and the element at that index represents the number of coins
 *     that add up to that subtotal. Therefore, we can set N[0] to 0
 *     because we know for certain that it takes 0 coins to get 0
 *     amount of money (this is the anchor/base case).
 * 
 * 3] For subtotals ranging from 1 to t, inclusive, do:
 *     For each coin:
 *       If coin <= subtotal and N[subtotal-coin]+1 < subtotal, then:
 *         N[subtotal] = N[subtotal-coin]+1
 * 
 *   Step 3 is known as the relaxation step. We started with an extreme
 *   and unrealistic assumption (i.e. that it takes infinite number of
 *   coins to make change for the money t), then we keep relaxing
 *   our assumptions until we get to the truth.
 * 
 * EXAMPLE: You should really skip the following manual example and go
 *   straight to the code. Then, if you need help seeing how the code
 *   is computing the number of coins for each subtotal, come back here.
 * 
 *   For t=10 and coins = {1,3,5}, the final version of N is:
 * 
 *   N[0] = 0; //base case             : 0 coins for 0 cent
 *   N[1] = N[0]+coins[0] = 0+1 = 1    : 1 coin for 1 cent   {1}
 *   N[2] = N[1]+coins[0] = 1+1 = 2    : 2 coins for 2 cents (1,1)
 *   N[3] = coins[1] = 1               : 1 coin for 3 cents  {3}
 *   N[4] = N[1]+coins[1] = 1+1 = 2    : 2 coins for 4 cents (3,1)
 *   N[5] = coins[2] = 1               : 1 coin for 5 cents {5}
 *   N[6] = N[5]+coins[0] = 1+1 = 2    : 2 coins for 6 cents (5,1)
 *   N[7] = N[6]+coins[0] = 2+1 = 3    : 3 coins for 7 cents (5,1,1)
 *   N[8] = N[5]+coins[2] = 1+1 = 2    : 2 coins for 8 cents (5,3)
 *   N[9] = N[8]+coins[0] = 2+1 = 3    : 3 coins for 9 cents (5,1,3)
 *   N[10] = N[5]+coins[2] = 1+1 = 2   : 2 coins for 10 cents (5,5)
 ********************************************************************/ 
 package algorithm.programming.dynamic;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class SubsetSum {

  /**
   * return makeExactChange(numberOfCoinsPerSubtotal(t, coins), t);
   **/
  public List<Integer> subsetSumOfCoins(int[] coins, int t) {
    int[] C = numberOfCoinsPerSubtotal(t, coins);
    return makeExactChange(C, t);
  }

  /**
   * Compute the number of coins in each subtotal amount of money 
   * from 0 to t.
   */
  private int[] numberOfCoinsPerSubtotal(int t, int[] coins) {
    int[] C = new int[t + 1];
    Arrays.fill(C, Integer.MAX_VALUE);
    C[0] = 0;// base case
    for (int coin : coins) {
      for (int subtotal = 1; subtotal <= t; subtotal++) {
        if (coin <= subtotal && C[subtotal] > C[subtotal - coin] + 1) {
          C[subtotal] = C[subtotal - coin] + 1;
        }
      }
    }
    return C;
  }

  /**
   * Now that we know how many coins it takes to get each subtotal
   * amount of money up to t, we can track the denomination of each coin:
   * keep subtracting the next subtotal that takes fewer coins than t.
   * For instance in the manual example above where t=10 and
   * coins = {1,3,5}; since t N[t=10] takes 2 coins, the next subtotal
   * that takes fewer coins than N[10] is N[5], and the next subtotal
   * that takes fewer coins than N[5] is N[0]. Hence the denominations
   * for N[10] are 10-5 and 5-0: {5,5}.
   **/
  private List<Integer> makeExactChange(int[] C, int t) {
    List<Integer> result = new ArrayList<Integer>();
    while (0 < C[t]) {
      int big = t;
      while (C[big] <= C[--t]);
      result.add(big - t);
    }
    return result;
  }
}
package algorithm.programming.dynamic;

import java.util.Arrays;
import java.util.List;
import static org.junit.Assert.*;
import org.junit.Test;

public class SubsetSumTest {

  /**
   * Test of subsetSumOfCoins method, of class SumOfCoins.
   */
  @Test
  public void testSubsetSumOfCoins() {
    System.out.println("subsetSumOfCoins");
    int[] coin = {1, 5, 10, 25};
    int t = 167;
    SubsetSum instance = new SubsetSum();
    List expResult = Arrays.asList(1, 1, 5, 10, 25, 25, 25, 25, 25, 25);
    List result = instance.subsetSumOfCoins(coin, t);
    assertEquals(expResult, result);
  }
}