Skip to content

Commit 4c59cf8

Browse files
authored
Create coin dispenser
1 parent 02a0134 commit 4c59cf8

File tree

1 file changed

+45
-0
lines changed

1 file changed

+45
-0
lines changed

interview_query/coin dispenser

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
Given a monetary amount in dollars and a list of coin denominations, write a function coin_exchange(amount: float, denominations: List[float]) -> List[Tuple[float, int]] that returns a list of tuples representing the optimal change amount. The denominations available for change can vary and are provided as input in the denominations list. A change is considered optimal when it returns the least possible count of denominations.
2+
3+
Note: The returned list of denominations should be in descending order, and in the case where there is no viable solution, return None.
4+
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
5+
6+
While it may not look like it, this question is actually an NP-Hard problem. What this means is that currently, there is no proof that an algorithm exists for this question in polynomial time. Trying to optimize your algorithm beyond this is impossible. For example, trying an iterative, greedy approach will only result in “false-failures” wherein an optimal solution exists, but is not found because of the greedy nature of the algorithm.
7+
8+
Inherently, the algorithm for this problem is basically an “explore all possibilities” algorithm, where we explore all possible permutations, starting from what we think is the most optimal until we get a valid solution. By doing this, the algorithm ensures the solution is indeed optimal because it has considered all other potential, yet non-viable, more optimal solutions.
9+
10+
Our full solution is the following:
11+
12+
def coin_exchange(amount: float, denominations: List[float], index: int = 0) -> List[Tuple[float, int]]:
13+
if amount == 0 or index >= len(denominations):
14+
return [] if amount == 0 else None
15+
16+
coin = denominations[index]
17+
max_count = int(amount // coin)
18+
19+
for count in range(max_count, -1, -1):
20+
remaining = round(amount - (coin * count), 2)
21+
22+
result = coin_exchange(remaining, denominations, index + 1)
23+
if result is not None:
24+
if count > 0:
25+
result.append((coin, count))
26+
result.sort(key=lambda x: x[0], reverse=True)
27+
return result
28+
29+
return None
30+
Note that we added another keyword parameter index in order to facilitate the backtracking.
31+
32+
If a coin combination doesn’t work, the function reduces the count of the current coin (at index) and tries again.
33+
The index parameter ensures that the function progresses through the coin denominations in an orderly fashion.
34+
The algorithm below considers two base cases:
35+
36+
Zero Amount: If the amount is zero, we’ve successfully found a way to make change, so we return an empty list.
37+
Exhausted Denominations: If index exceeds the number of denominations, it means we’ve tried all options without success, so we return None.
38+
Here’s how we find the optimal count:
39+
40+
We iterate over the number of times we can use the current coin (denomination at index), starting from the maximum count down to zero. We start at the max count of the current coin as this is the most optimal (albeit not guaranteed to be valid) solution.
41+
For each count, we compute the remaining amount after using that number of the current coin.
42+
The function calls itself for the next denomination, increasing the index by 1. This shift to the next coin is controlled by the index parameter.
43+
If this recursive call finds a valid combination (returns a list instead of None), we know we’re on the right track.
44+
If a certain count of the current coin is used in the solution, it’s added to the result list.
45+
Results are sorted by coin denomination for clarity.

0 commit comments

Comments
 (0)