Vipin
Vipin

Reputation: 5233

minimum number of coins to make change

I am trying to print the minimum number of coins to make the change, if not possible print -1

In this code variable int[] c (coins array) has denominations I can use to come up with Total sum.

int total has total sum I need to come up with using coins (Unlimited supply)

    public static int mincoinDP(int[] c, int total) {
        int[][] a = new int[c.length + 1][total + 1];

        for (int i = 0; i <= c.length; i++) {
            a[i][0] = 0;
        }
        for (int j = 1; j <= total; j++) {
            a[0][j] = Integer.MAX_VALUE - total;
        }

        for (int i = 1; i <= c.length; i++) {
            for (int j = 1; j <= total; j++) {
                if (c[i - 1] > j) {
                    a[i][j] = Integer.MAX_VALUE - total;
                } else {
                    a[i][j] = Math.min(a[i - 1][j], 1 + a[i][j - c[i - 1]]);
                }
            }
        }

        return a[c.length][total];
    }

For Sum : 4759 and Array: {31 90 8 36} Correct output is: 59 My output is: 60

What is wrong in code ?

Below is my recursive solution, trying to apply same logic in DP solution. Something seems to be wrong in logic here as well. For same input it prints -2147483595

    public static void main(String[] args) {
        int[] array = new int[] {31, 90, 8, 36};
        System.out.println(mincoin(array, 4759, 0));
    }

    public static int mincoin(int[] c, int total, int i) {

        if (total == 0) return 0;
        if (i >= c.length) return Integer.MAX_VALUE;


        int x = Integer.MAX_VALUE, y = Integer.MAX_VALUE;

        if (total - c[i] >= 0) {
            x = 1 + mincoin(c, total - c[i], i);
        }
        y = mincoin(c, total, i + 1);

        return Math.min(x, y);
    }

Edit: Problems in code were:

  1. DP version: if (c[i -1] > j) , It is case when solution is not possible choosing this coin: Here we should accept solution without this coin which is a[i-1][j]
  2. Recursive version: if(i >= c.length), it is terminating condition when we dont any coin at this position, here we should return infinity (Integer.MAX_VALUE) and to avoid integer overflow return Integer.MAX_VALUE - total.

Though I dont like this version of infinity, but dont see any nice way other than this here.

Upvotes: 0

Views: 1275

Answers (2)

Prashant
Prashant

Reputation: 167

Just in case someone looking for solution

public int coinChange(int[] coins, int amount) {
    int dp[][] = new int[coins.length+1][amount+1];
    Arrays.sort(coins);
    
    // First column of every row
    for (int i = 0; i < coins.length; ++i) {
        dp[i][0] = 0;
    }

    /*
       Setting this so that this is default max value. We always
       want our dp[i][j] better than this
    */
    for (int j = 0; j <= amount; ++j) {
        dp[0][j] = amount+1;
    }
    
    for (int i = 1; i <= coins.length; ++i) {
        for (int j = 1; j <= amount; ++j) {
            if (coins[i-1] > j) {
               dp[i][j] = dp[i-1][j];   // Take the already best value in above row
            } else {
               dp[i][j] = Math.min(dp[i-1][j], 1 + dp[i][j-coins[i-1]]); // Take the best of above row and using current coin
            }
        }
    }
    if (dp[coins.length][amount] > amount) { // it means we cannot find any coin
        return -1;
    } else {
        return dp[coins.length][amount];
    }
}

Upvotes: 0

Paul Hankin
Paul Hankin

Reputation: 58349

It looks like you're using dynamic programming, with a[i][j] intended to represent the minimum number of coins (using the first i denominations) that sum to j. But I think your recurrence relations are off. They should be:

a[0][j] = 0 if j==0, otherwise infinity

a[i][j] = a[i-1][j] if c[i-1] > j
a[i][j] = min(a[i-1][j], 1 + a[i][j-c[i-1]]) if c[i-1] <= j

The main mistake is the if c[i-1] > j case in your code. You set the value to infinity (or your variant of infinity), but you should just copy the minimum number of coins from the previous row since you may be able to construct the total using the smaller number of coins.

By the way, there is a neater way to write this code. In pseudocode:

a = new int[total+1]
for int j = 1 to total+1 {
    a[j] = infinity
}
for int coin in coins {
    for j = coin to total+1 {
        a[j] = min(a[j], a[j-coin]+1)
    }
}

It's essentially the same algorithm, but it uses a smaller one-dimensional array which it modifies in-place.

Upvotes: 1

Related Questions