2-7-2018 Change Problem


change problem means find the minimum number of coins needed to make change.

Coin change

This is a very classic dynamic programming algorithm. However, for someone not familiar with the concept, it can be tricky. Here we tackle the problem recursively, for each coin, if I take that coin into account, then the fewest number of coins we can get is 1+coinChange(amount-that_coin_value). So for all the coins, we return the smallest number as min(1+coinChange(amount-coin1_value), 1+coinChange(amount-coin2_value, …).

As we can see it is recursive, the solution is as below, this solution of upper time complexity O(c^n) where c is number of different denominations and n is the amount given, which is exponential:

state: F(S): minimum number of coins needed to make change for amount S using coin denominations[c0, ...cn - 1];

transit function: F(S) = F(S - C) + 1. we compute each F(S - Ci) for each possible denomination c0,c1,c2,...cn-1. And choose minimum among them.

In the recursion tree above, we could see that a lot of subproblems were calculated multiple times. Therefore we should cache the solutions to the subproblems in a table and access them in constant time when necessary.

class Solution {
    public int coinChange(int[] coins, int amount) {
        if (coins == null || coins.length == 0) return 0;
        if (amount < 1) return 0;

        return change(coins, amount, new int[amount]);
    }

    // rem: remaining coins after the last step.
    // count[rem] : 
    private int change(int[] coins, int rem, int[] count) {
        // base case
        if (rem < 0) return -1;
        if (rem == 0) return 0;  // pay attention: should return 0.
        if (count[rem - 1] != 0) return count[rem - 1]; // already computed, so reuse.

        // recursive case
        int min = Integer.MAX_VALUE;
        for (int coin : coins) {
            int res = change(coins, rem - coin, count);
            if (res >= 0 && res < min) {
                min = 1 + res;
            }
        }
        count[rem - 1] = (min == Integer.MAX_VALUE) ? -1 : min;
        return count[rem - 1];
    }
}

Time complexity is O(S*n) Space complexity is O(S)

Or we can use Dynamic Programming bottom-up approach.

Before calculating F(i), we have to compute all minimum counts for amounts up to i, On each iteration i of the algorithm F(i) is computed as min F(i - cj) + 1.

F(3)=min{F(3−c1),F(3−c2),F(3−c3)}+1
    =min{F(3−1),F(3−2),F(3−3)}+1
    =min{F(2),F(1),F(0)}+1
    =min{1,1,0}+1
    =1
public class Solution {
    public int coinChange(int[] coins, int amount) {
        int max = amount + 1;             
        int[] dp = new int[amount + 1];  
        Arrays.fill(dp, max);  
        dp[0] = 0;   
        for (int i = 1; i <= amount; i++) {
            for (int j = 0; j < coins.length; j++) {
                if (coins[j] <= i) {
                    dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1);
                }
            }
        }
        return dp[amount] > amount ? -1 : dp[amount];
    }
}

results matching ""

    No results matching ""