|
| 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`. |
0 commit comments