|
| 1 | +package Dynamic_Programming.Unbounded_Knapsack; |
| 2 | + |
| 3 | +// Problem Statement: Minimum Coin Change |
| 4 | +// LeetCode Question: 322. Coin Change |
| 5 | + |
| 6 | +public class Problem_4_Minimum_Coin_Change { |
| 7 | + // Brute-Force solution |
| 8 | + class Solution_1 { |
| 9 | + |
| 10 | + public int countChange(int[] denominations, int total) { |
| 11 | + int result = this.countChangeRecursive(denominations, total, 0); |
| 12 | + return (result == Integer.MAX_VALUE ? -1 : result); |
| 13 | + } |
| 14 | + |
| 15 | + private int countChangeRecursive(int[] denominations, int total, int currentIndex) { |
| 16 | + // base check |
| 17 | + if (total == 0) |
| 18 | + return 0; |
| 19 | + |
| 20 | + if(denominations.length == 0 || currentIndex >= denominations.length) |
| 21 | + return Integer.MAX_VALUE; |
| 22 | + |
| 23 | + // recursive call after selecting the coin at the currentIndex |
| 24 | + // if the coin at currentIndex exceeds the total, we shouldn't process this |
| 25 | + int count1 = Integer.MAX_VALUE; |
| 26 | + if( denominations[currentIndex] <= total ) { |
| 27 | + int res = countChangeRecursive(denominations, total - denominations[currentIndex], currentIndex); |
| 28 | + if(res != Integer.MAX_VALUE){ |
| 29 | + count1 = res + 1; |
| 30 | + } |
| 31 | + } |
| 32 | + |
| 33 | + // recursive call after excluding the coin at the currentIndex |
| 34 | + int count2 = countChangeRecursive(denominations, total, currentIndex + 1); |
| 35 | + |
| 36 | + return Math.min(count1, count2); |
| 37 | + } |
| 38 | + |
| 39 | + } |
| 40 | + |
| 41 | + // Top-down Dynamic Programming with Memoization |
| 42 | + class Solution_2 { |
| 43 | + |
| 44 | + public int countChange(int[] denominations, int total) { |
| 45 | + Integer[][] dp = new Integer[denominations.length][total + 1]; |
| 46 | + int result = this.countChangeRecursive(dp, denominations, total, 0); |
| 47 | + return (result == Integer.MAX_VALUE ? -1 : result); |
| 48 | + } |
| 49 | + |
| 50 | + private int countChangeRecursive(Integer[][] dp, int[] denominations, int total, int currentIndex) { |
| 51 | + // base check |
| 52 | + if (total == 0) |
| 53 | + return 0; |
| 54 | + |
| 55 | + if(denominations.length == 0 || currentIndex >= denominations.length) |
| 56 | + return Integer.MAX_VALUE; |
| 57 | + |
| 58 | + // check if we have not already processed a similar sub-problem |
| 59 | + if(dp[currentIndex][total] == null) { |
| 60 | + // recursive call after selecting the coin at the currentIndex |
| 61 | + // if the coin at currentIndex exceeds the total, we shouldn't process this |
| 62 | + int count1 = Integer.MAX_VALUE; |
| 63 | + if( denominations[currentIndex] <= total ) { |
| 64 | + int res = countChangeRecursive(dp, denominations, total - denominations[currentIndex], currentIndex); |
| 65 | + if(res != Integer.MAX_VALUE){ |
| 66 | + count1 = res + 1; |
| 67 | + } |
| 68 | + } |
| 69 | + |
| 70 | + // recursive call after excluding the coin at the currentIndex |
| 71 | + int count2 = countChangeRecursive(dp, denominations, total, currentIndex + 1); |
| 72 | + dp[currentIndex][total] = Math.min(count1, count2); |
| 73 | + } |
| 74 | + return dp[currentIndex][total]; |
| 75 | + } |
| 76 | + |
| 77 | + } |
| 78 | + |
| 79 | + // Bottom-up Dynamic Programming |
| 80 | + |
| 81 | + class Solution_3 { |
| 82 | + |
| 83 | + public int countChange(int[] denominations, int total) |
| 84 | + { |
| 85 | + int n = denominations.length; |
| 86 | + int[][] dp = new int[n][total + 1]; |
| 87 | + |
| 88 | + for(int i=0; i < n; i++) |
| 89 | + for(int j=0; j <= total; j++) |
| 90 | + dp[i][j] = Integer.MAX_VALUE; |
| 91 | + |
| 92 | + // populate the total=0 columns, as we don't need any coin to make zero total |
| 93 | + for(int i=0; i < n; i++) |
| 94 | + dp[i][0] = 0; |
| 95 | + |
| 96 | + for(int i=0; i < n; i++) { |
| 97 | + for(int t=1; t <= total; t++) { |
| 98 | + if(i > 0) |
| 99 | + dp[i][t] = dp[i-1][t]; //exclude the coin |
| 100 | + if(t >= denominations[i]) { |
| 101 | + if(dp[i][t-denominations[i]] != Integer.MAX_VALUE) |
| 102 | + dp[i][t] = Math.min(dp[i][t], dp[i][t-denominations[i]]+1); // include the coin |
| 103 | + } |
| 104 | + } |
| 105 | + } |
| 106 | + |
| 107 | + // total combinations will be at the bottom-right corner. |
| 108 | + return (dp[n-1][total] == Integer.MAX_VALUE ? -1 : dp[n-1][total]); |
| 109 | + } |
| 110 | + |
| 111 | + } |
| 112 | + |
| 113 | + |
| 114 | +} |
0 commit comments