-
-
Notifications
You must be signed in to change notification settings - Fork 682
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5e5d444
commit 109a4c2
Showing
4 changed files
with
152 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
{ | ||
"introduction": { | ||
"authors": [ | ||
"jagdish-15" | ||
] | ||
}, | ||
"approaches": [ | ||
{ | ||
"uuid": "d0b615ca-3a02-4d66-ad10-e0c513062189", | ||
"slug": "dynamic-programming", | ||
"title": "Dynamic Programming Approach", | ||
"blurb": "Use dynamic programming to find the most efficient change combination.", | ||
"authors": [ | ||
"jagdish-15" | ||
], | ||
"contributors": [ | ||
"kahgoh" | ||
] | ||
} | ||
] | ||
} |
68 changes: 68 additions & 0 deletions
68
exercises/practice/change/.approaches/dynamic-programming/content.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
# Dynamic Programming Approach | ||
|
||
```java | ||
import java.util.List; | ||
import java.util.ArrayList; | ||
|
||
class ChangeCalculator { | ||
private final List<Integer> currencyCoins; | ||
|
||
ChangeCalculator(List<Integer> currencyCoins) { | ||
this.currencyCoins = currencyCoins; | ||
} | ||
|
||
List<Integer> computeMostEfficientChange(int grandTotal) { | ||
if (grandTotal < 0) | ||
throw new IllegalArgumentException("Negative totals are not allowed."); | ||
|
||
List<List<Integer>> coinsUsed = new ArrayList<>(grandTotal + 1); | ||
coinsUsed.add(new ArrayList<Integer>()); | ||
|
||
for (int i = 1; i <= grandTotal; i++) { | ||
List<Integer> bestCombination = null; | ||
for (int coin: currencyCoins) { | ||
if (coin <= i && coinsUsed.get(i - coin) != null) { | ||
List<Integer> currentCombination = new ArrayList<>(coinsUsed.get(i - coin)); | ||
currentCombination.add(0, coin); | ||
if (bestCombination == null || currentCombination.size() < bestCombination.size()) | ||
bestCombination = currentCombination; | ||
} | ||
} | ||
coinsUsed.add(bestCombination); | ||
} | ||
|
||
if (coinsUsed.get(grandTotal) == null) | ||
throw new IllegalArgumentException("The total " + grandTotal + " cannot be represented in the given currency."); | ||
|
||
return coinsUsed.get(grandTotal); | ||
} | ||
} | ||
``` | ||
|
||
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. | ||
It minimizes the number of coins needed by breaking down the problem into smaller subproblems and solving them progressively. | ||
|
||
## Explanation | ||
|
||
### Initialize Coins Usage Tracker | ||
|
||
- If the `grandTotal` is negative, an exception is thrown immediately. | ||
- We create a list `coinsUsed`, where each index `i` stores the most efficient combination of coins that sum up to the value `i`. | ||
- The list is initialized with an empty list at index `0`, as no coins are needed to achieve a total of zero. | ||
|
||
### Iterative Dynamic Programming | ||
|
||
- 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`. | ||
- 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). | ||
- 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. | ||
|
||
### Result | ||
|
||
- After processing all values up to `grandTotal`, the combination at `coinsUsed[grandTotal]` will represent the most efficient solution. | ||
- If no valid combination exists for `grandTotal`, an exception is thrown. | ||
|
||
## Time and Space Complexity | ||
|
||
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`. | ||
|
||
The space complexity is **O(n)** due to the list `coinsUsed`, which stores the most efficient coin combination for each total up to `grandTotal`. |
8 changes: 8 additions & 0 deletions
8
exercises/practice/change/.approaches/dynamic-programming/snippet.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
class ChangeCalculator { | ||
private final List<Integer> currencyCoins; | ||
|
||
ChangeCalculator(List<Integer> currencyCoins) { | ||
this.currencyCoins = currencyCoins; | ||
} | ||
// computeMostEfficientChange method | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
# Introduction | ||
|
||
There is an idiomatic approach to solving "Change." | ||
You can use [dynamic programming][dynamic-programming] to calculate the minimum number of coins required for a given total. | ||
|
||
## General guidance | ||
|
||
The key to solving "Change" is understanding that not all totals can be reached with the available coin denominations. | ||
The solution needs to figure out which totals can be achieved and how to combine the coins optimally. | ||
|
||
## Approach: Dynamic Programming | ||
|
||
```java | ||
import java.util.List; | ||
import java.util.ArrayList; | ||
|
||
class ChangeCalculator { | ||
private final List<Integer> currencyCoins; | ||
|
||
ChangeCalculator(List<Integer> currencyCoins) { | ||
this.currencyCoins = currencyCoins; | ||
} | ||
|
||
List<Integer> computeMostEfficientChange(int grandTotal) { | ||
if (grandTotal < 0) | ||
throw new IllegalArgumentException("Negative totals are not allowed."); | ||
|
||
List<List<Integer>> coinsUsed = new ArrayList<>(grandTotal + 1); | ||
coinsUsed.add(new ArrayList<Integer>()); | ||
|
||
for (int i = 1; i <= grandTotal; i++) { | ||
List<Integer> bestCombination = null; | ||
for (int coin: currencyCoins) { | ||
if (coin <= i && coinsUsed.get(i - coin) != null) { | ||
List<Integer> currentCombination = new ArrayList<>(coinsUsed.get(i - coin)); | ||
currentCombination.add(0, coin); | ||
if (bestCombination == null || currentCombination.size() < bestCombination.size()) | ||
bestCombination = currentCombination; | ||
} | ||
} | ||
coinsUsed.add(bestCombination); | ||
} | ||
|
||
if (coinsUsed.get(grandTotal) == null) | ||
throw new IllegalArgumentException("The total " + grandTotal + " cannot be represented in the given currency."); | ||
|
||
return coinsUsed.get(grandTotal); | ||
} | ||
} | ||
``` | ||
|
||
For a detailed look at the code and logic, see the full explanation in the [Dynamic Programming Approach][approach-dynamic-programming]. | ||
|
||
[approach-dynamic-programming]: https://exercism.org/tracks/java/exercises/change/approaches/dynamic-programming | ||
[dynamic-programming]: https://en.wikipedia.org/wiki/Dynamic_programming |