1- from typing import List
1+ from typing import Dict , Tuple
2+
3+ COINS = [200 , 100 , 50 , 20 , 10 , 5 , 2 , 1 ]
4+
25
36def ways_to_make_change (total : int ) -> int :
47 """
5- Given access to coins with the values 1, 2, 5, 10, 20, 50, 100, 200,
6- returns a count of all of the ways to make the passed total value.
8+ Returns the number of ways to make `total` using UK coin values.
79 """
8- cache = {}
9- return ways_to_make_change_helper (total , [ 200 , 100 , 50 , 20 , 10 , 5 , 2 , 1 ] , cache )
10+ cache : Dict [ Tuple [ int , int ], int ] = {}
11+ return _helper (total , 0 , cache )
1012
1113
12- def ways_to_make_change_helper (total : int , coins : List [ int ] , cache : dict ) -> int :
14+ def _helper (total : int , coin_index : int , cache : Dict [ Tuple [ int , int ], int ] ) -> int :
1315 """
14- Helper function with memoization.
15- Cache key is (total, index of first coin in list) — but since we pass
16- the coins list by slicing, we can cache using tuple(total, tuple(coins)).
16+ Recursive helper using memoization.
17+
18+ Parameters:
19+ - total: remaining amount to form
20+ - coin_index: index into COINS representing which coins we are allowed to use
21+ - cache: memoization dictionary
1722 """
1823
19- key = (total , tuple (coins ))
24+ # Base case: exact match
25+ if total == 0 :
26+ return 1
27+
28+ # Base case: no coins left
29+ if coin_index == len (COINS ):
30+ return 0
2031
32+ key = (total , coin_index )
33+
34+ # If we’ve already solved: return the cached result, We just return the stored answer instead of recomputing it
2135 if key in cache :
2236 return cache [key ]
2337
24- if total == 0 or len (coins ) == 0 :
25- return 0
26-
38+ # CORE LOGIC:
2739 ways = 0
28- for coin_index in range (len (coins )):
29- coin = coins [coin_index ]
30- count_of_coin = 1
31- while coin * count_of_coin <= total :
32- total_from_coins = coin * count_of_coin
33- if total_from_coins == total :
34- ways += 1
35- else :
36- intermediate = ways_to_make_change_helper (
37- total - total_from_coins ,
38- coins = coins [coin_index + 1 :],
39- cache = cache
40- )
41- ways += intermediate
42- count_of_coin += 1
40+ coin = COINS [coin_index ]
41+
42+ # Try using this coin 0, 1, 2, ... times
43+ # The maximum number of this coin we could use without exceeding total.
44+ max_count = total // coin
45+
46+ # For each possible count of this coin, we compute the remaining amount and recursively call _helper for the next coin.
47+ for count in range (max_count + 1 ):
48+ remaining = total - (coin * count )
49+ ways += _helper (remaining , coin_index + 1 , cache )
4350
4451 cache [key ] = ways
4552 return ways
0 commit comments