Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding approach change #2859

Open
wants to merge 27 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
e3cbf38
Adding approach change
jagdish-15 Nov 9, 2024
4a7811f
Fixing typo in filename
jagdish-15 Nov 9, 2024
e8d2787
Fixing style errors
jagdish-15 Nov 9, 2024
6152c10
Fixing style errors
jagdish-15 Nov 9, 2024
5d398d0
Fixing stle errors
jagdish-15 Nov 9, 2024
115a331
Fixing file names
jagdish-15 Nov 9, 2024
d2c2451
Adding uuid for approach of change
jagdish-15 Nov 14, 2024
b3a98df
Adding snippet for approach of change
jagdish-15 Nov 14, 2024
e338ff2
Merge branch 'main' into add-approach-change
jagdish-15 Nov 14, 2024
9438325
Updating approach files
jagdish-15 Nov 15, 2024
fde837b
Fixing styling errors
jagdish-15 Nov 15, 2024
7ec2960
Adding approach change
jagdish-15 Nov 9, 2024
404de05
Fixing typo in filename
jagdish-15 Nov 9, 2024
1aa6d9c
Fixing style errors
jagdish-15 Nov 9, 2024
2fbec2a
Fixing style errors
jagdish-15 Nov 9, 2024
c1d07e5
Fixing stle errors
jagdish-15 Nov 9, 2024
afee45a
Fixing file names
jagdish-15 Nov 9, 2024
d9694fa
Adding uuid for approach of change
jagdish-15 Nov 14, 2024
7aa412e
Adding snippet for approach of change
jagdish-15 Nov 14, 2024
f3eb007
Updating approach files
jagdish-15 Nov 15, 2024
0b5b6f2
Fixing styling errors
jagdish-15 Nov 15, 2024
2df72c4
Merge branch 'add-approach-change' of https://github.com/jagdish-15/j…
jagdish-15 Nov 18, 2024
2758bc3
Updating approaches for Change after feedback
jagdish-15 Nov 18, 2024
c0a46c6
Fixing styling issues for approache for Change
jagdish-15 Nov 18, 2024
f76ad5d
Update exercises/practice/change/.approaches/dynamic-programming/cont…
jagdish-15 Nov 19, 2024
5db8204
Update exercises/practice/change/.approaches/dynamic-programming/cont…
jagdish-15 Nov 19, 2024
505a92d
Updating content for dynamic approach of change
jagdish-15 Nov 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions exercises/practice/change/.approaches/config.json
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": [
"kagoh"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"kagoh"
"kahgoh"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am sorry for the oversight.

]
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Dynamic Programming Approach

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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at how we have written the content for some of other approaches (like boolean chain for leap, bit shifting for grains and if statements for Bob, I'd suggest moving the code up here, just under the heading. The description of the approach then begins just under it.

Also, we generally use one sentence per line in our Markdown content. For example:

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I will move the code to the top and start the explanation afterward. I have also used new lines for every sentence separately, except when it is in a bullet point.


This approach ensures that we find the most efficient way to make change and handles edge cases where no solution exists.

## Explanation

1. **Initialize Coins Usage Tracker**:

- 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.

2. **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.

3. **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.

```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);
}
}
```

## Key Points
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the core of this document should be focusing on the specifics of how the approach works. From that point of view, I think the Key Points heading/section is confusing as Time Complexity and Space Complexity isn't a core part of the implementation, but I do think we can certainly mention them. Perhaps we could remove the heading.

Suggested change
## Key Points

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I've removed this heading.


- **Time 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`.

- **Space Complexity**: The space complexity is **O(n)** due to the list `coinsUsed`, which stores the most efficient coin combination for each total up to `grandTotal`.

- **Edge Cases**:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest moving the points from the edge cases to be with your explanation as they are part of the implementation details. Idalso suggest separating them to follow the order of the code to make it easier to follow (i.e putting the point about checking if grandTotal is negative to the top and one about if no exact total to the bottom of the explanation).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've moved the first point to the start of the explanation as you suggested and removed the second point since it's already covered at the end, just before the 'Time Complexity' section.


- If the `grandTotal` is negative, an exception is thrown immediately.
- If there is no way to make the exact total with the given denominations, an exception is thrown with a descriptive message.

## Trade-offs and Considerations

- **Efficiency**: This approach is highly efficient in terms of minimizing the number of coins, but it might require significant memory for larger `grandTotal` values, as the space complexity grows linearly with `grandTotal`.

- **Alternative Approaches**:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please remove this section on alternative approaches? This should just focus on the dynamic programming approach as this will become the dynamic programming page. Alternatively, we could move it to a Which approach to use? section in the introduction.md (similar to the isogram or robot name approaches), but we probably should briefly describe the Greedy Approach if we do (and we could possibly move the point about the efficiency there too).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have removed both the "Efficiency" and "Alternative Approach" sections entirely. I agree that it makes more sense to include these points in the introduction file under a section like "Which Approach to Use?" However, I believe this should be done only after we add another approach to compare. For now, with just a single approach, these sections are unnecessary.


- A **Greedy Approach** could be faster for some cases but does not always guarantee the minimum number of coins.
- This dynamic programming approach is best when the goal is to guarantee the fewest coins possible, especially when no simple greedy solution exists.

## Conclusion

The dynamic programming approach provides an optimal solution for the change-making problem, ensuring that we minimize the number of coins used while efficiently solving the problem for any `grandTotal`. However, it’s essential to consider the trade-offs in terms of memory usage and the time complexity when dealing with very large inputs.
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
}
26 changes: 26 additions & 0 deletions exercises/practice/change/.approaches/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Introduction to Change Calculator
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This suggestion is to make the heading consistent with our other existing approaches.

Suggested change
# Introduction to Change Calculator
# Introduction

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed!!


In the "Change Calculator" exercise, the goal is to determine the minimum number of coins needed to reach a given total using a specific set of coin denominations. This is a classic problem in dynamic programming, where efficient change-making is essential, especially when there are constraints on coin types or large totals.

## Problem Overview
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to repeat the exercise here. The other approaches generally have a "General guidance" section that talks about the "key things" to solve the exercise - things that all approaches are likely to have to. For example, in leap, it is as simple as knowing whether a year is divisible by 400, 100 and 4. For grains, its knowing that each square is doubled.

For Change, it could be that not all totals can be reached and somehow figuring out which ones can be reached and how.

Suggested change
## Problem Overview
## General guidance

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I've changed it.


Given:

- A list of coin denominations, each representing an available currency unit.
- A total amount (`grandTotal`) we want to reach using the fewest possible coins from the given denominations.

jagdish-15 marked this conversation as resolved.
Show resolved Hide resolved
The solution should find the optimal combination of coins to match the total. If it's impossible to match the total exactly, the solution should indicate this by throwing an exception.

## Approach Overview
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other approaches generally have a short listing of all the approaches here, with a link to the specific approach's page just underneath. For example, this would normally be a code listing for your dynamic programming approach followed by a link to the page generated from dynamic-programming/content.md (the URL would be https://exercism.org/tracks/java/exercises/change/approaches/dynamic-programming).

Suggested change
## Approach Overview
## Approach: Dynamic programming


Our solution uses a **dynamic programming approach**, where we systematically build up the optimal combinations for all totals from `0` up to the target amount (`grandTotal`). For each total, we track the fewest coins needed to make that total, reusing previous results to make the solution efficient.

This approach ensures that we find the minimum number of coins required in a structured, repeatable way, avoiding the need for complex recursive calls or excessive backtracking.

## Key Features of the Approach

- **Efficiency**: By building solutions for each increment up to `grandTotal`, this approach minimizes redundant calculations.
- **Flexibility**: Handles cases where exact change is impossible by checking at each step.
- **Scalability**: Works for various coin denominations and totals, though large inputs may impact performance.

For a detailed look at the code and logic, see the full explanation in the [approach file](https://exercism.org/tracks/java/exercises/change/approaches/dynamic-programming).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In regards to the approach file link, there is a preference to use reference linking to make maintenance easier.

I also suggest changing the link text to "Dynamic Programming approach" as students will see a web page based on your content.md (and not the content.md "file").

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, and I've made the changes accordingly.