Skip to content

Commit 109a4c2

Browse files
authored
Add approach for change (#2859)
1 parent 5e5d444 commit 109a4c2

File tree

4 files changed

+152
-0
lines changed

4 files changed

+152
-0
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"introduction": {
3+
"authors": [
4+
"jagdish-15"
5+
]
6+
},
7+
"approaches": [
8+
{
9+
"uuid": "d0b615ca-3a02-4d66-ad10-e0c513062189",
10+
"slug": "dynamic-programming",
11+
"title": "Dynamic Programming Approach",
12+
"blurb": "Use dynamic programming to find the most efficient change combination.",
13+
"authors": [
14+
"jagdish-15"
15+
],
16+
"contributors": [
17+
"kahgoh"
18+
]
19+
}
20+
]
21+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# Dynamic Programming Approach
2+
3+
```java
4+
import java.util.List;
5+
import java.util.ArrayList;
6+
7+
class ChangeCalculator {
8+
private final List<Integer> currencyCoins;
9+
10+
ChangeCalculator(List<Integer> currencyCoins) {
11+
this.currencyCoins = currencyCoins;
12+
}
13+
14+
List<Integer> computeMostEfficientChange(int grandTotal) {
15+
if (grandTotal < 0)
16+
throw new IllegalArgumentException("Negative totals are not allowed.");
17+
18+
List<List<Integer>> coinsUsed = new ArrayList<>(grandTotal + 1);
19+
coinsUsed.add(new ArrayList<Integer>());
20+
21+
for (int i = 1; i <= grandTotal; i++) {
22+
List<Integer> bestCombination = null;
23+
for (int coin: currencyCoins) {
24+
if (coin <= i && coinsUsed.get(i - coin) != null) {
25+
List<Integer> currentCombination = new ArrayList<>(coinsUsed.get(i - coin));
26+
currentCombination.add(0, coin);
27+
if (bestCombination == null || currentCombination.size() < bestCombination.size())
28+
bestCombination = currentCombination;
29+
}
30+
}
31+
coinsUsed.add(bestCombination);
32+
}
33+
34+
if (coinsUsed.get(grandTotal) == null)
35+
throw new IllegalArgumentException("The total " + grandTotal + " cannot be represented in the given currency.");
36+
37+
return coinsUsed.get(grandTotal);
38+
}
39+
}
40+
```
41+
42+
The **Dynamic Programming (DP)** approach is an efficient way to solve the problem of making change for a given total using a list of available coin denominations.
43+
It minimizes the number of coins needed by breaking down the problem into smaller subproblems and solving them progressively.
44+
45+
## Explanation
46+
47+
### Initialize Coins Usage Tracker
48+
49+
- If the `grandTotal` is negative, an exception is thrown immediately.
50+
- We create a list `coinsUsed`, where each index `i` stores the most efficient combination of coins that sum up to the value `i`.
51+
- The list is initialized with an empty list at index `0`, as no coins are needed to achieve a total of zero.
52+
53+
### Iterative Dynamic Programming
54+
55+
- For each value `i` from 1 to `grandTotal`, we explore all available coin denominations to find the best combination that can achieve the total `i`.
56+
- For each coin, we check if it can be part of the solution (i.e., if `coin <= i` and `coinsUsed[i - coin]` is a valid combination).
57+
- If so, we generate a new combination by adding the current coin to the solution for `i - coin`. We then compare the size of this new combination with the existing best combination and keep the one with fewer coins.
58+
59+
### Result
60+
61+
- After processing all values up to `grandTotal`, the combination at `coinsUsed[grandTotal]` will represent the most efficient solution.
62+
- If no valid combination exists for `grandTotal`, an exception is thrown.
63+
64+
## Time and Space Complexity
65+
66+
The time complexity of this approach is **O(n * m)**, where `n` is the `grandTotal` and `m` is the number of available coin denominations. This is because we iterate over all coin denominations for each amount up to `grandTotal`.
67+
68+
The space complexity is **O(n)** due to the list `coinsUsed`, which stores the most efficient coin combination for each total up to `grandTotal`.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
class ChangeCalculator {
2+
private final List<Integer> currencyCoins;
3+
4+
ChangeCalculator(List<Integer> currencyCoins) {
5+
this.currencyCoins = currencyCoins;
6+
}
7+
// computeMostEfficientChange method
8+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Introduction
2+
3+
There is an idiomatic approach to solving "Change."
4+
You can use [dynamic programming][dynamic-programming] to calculate the minimum number of coins required for a given total.
5+
6+
## General guidance
7+
8+
The key to solving "Change" is understanding that not all totals can be reached with the available coin denominations.
9+
The solution needs to figure out which totals can be achieved and how to combine the coins optimally.
10+
11+
## Approach: Dynamic Programming
12+
13+
```java
14+
import java.util.List;
15+
import java.util.ArrayList;
16+
17+
class ChangeCalculator {
18+
private final List<Integer> currencyCoins;
19+
20+
ChangeCalculator(List<Integer> currencyCoins) {
21+
this.currencyCoins = currencyCoins;
22+
}
23+
24+
List<Integer> computeMostEfficientChange(int grandTotal) {
25+
if (grandTotal < 0)
26+
throw new IllegalArgumentException("Negative totals are not allowed.");
27+
28+
List<List<Integer>> coinsUsed = new ArrayList<>(grandTotal + 1);
29+
coinsUsed.add(new ArrayList<Integer>());
30+
31+
for (int i = 1; i <= grandTotal; i++) {
32+
List<Integer> bestCombination = null;
33+
for (int coin: currencyCoins) {
34+
if (coin <= i && coinsUsed.get(i - coin) != null) {
35+
List<Integer> currentCombination = new ArrayList<>(coinsUsed.get(i - coin));
36+
currentCombination.add(0, coin);
37+
if (bestCombination == null || currentCombination.size() < bestCombination.size())
38+
bestCombination = currentCombination;
39+
}
40+
}
41+
coinsUsed.add(bestCombination);
42+
}
43+
44+
if (coinsUsed.get(grandTotal) == null)
45+
throw new IllegalArgumentException("The total " + grandTotal + " cannot be represented in the given currency.");
46+
47+
return coinsUsed.get(grandTotal);
48+
}
49+
}
50+
```
51+
52+
For a detailed look at the code and logic, see the full explanation in the [Dynamic Programming Approach][approach-dynamic-programming].
53+
54+
[approach-dynamic-programming]: https://exercism.org/tracks/java/exercises/change/approaches/dynamic-programming
55+
[dynamic-programming]: https://en.wikipedia.org/wiki/Dynamic_programming

0 commit comments

Comments
 (0)