Skip to content

Commit 71ca456

Browse files
committed
Two-Hundred-Seventy-Two Commit: Add Minimum Coin Change problem to Unbounded Knapsack section
1 parent fe9eea0 commit 71ca456

File tree

1 file changed

+114
-0
lines changed

1 file changed

+114
-0
lines changed
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
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

Comments
 (0)