Sheffield | 25-SDC-Nov | Sheida Shabankari | Sprint 2 |improve with caches#112
Sheffield | 25-SDC-Nov | Sheida Shabankari | Sprint 2 |improve with caches#112sheida-shab wants to merge 3 commits intoCodeYourFuture:mainfrom
Conversation
|
|
||
|
|
||
| def ways_to_make_change_helper(total: int, coins: List[int]) -> int: | ||
| def ways_to_make_change_helper(total: int, coins: List[int],cache=None) -> int: |
There was a problem hiding this comment.
Why not use {} as the default value for cache?
There was a problem hiding this comment.
If I use {} as the default value, the cache is shared between all function calls .
Not only between recursive calls, but between every call to the function in the whole program.
This happens because default arguments in Python are created once, when the function is defined.
If I use None instead, then every time ways_to_make_change is called,
a new cache dictionary is created.
At the same time, all recursive calls share that same cache,
which is exactly what we want for memoisation .
There was a problem hiding this comment.
Thanks for clarification. I didn't know that.
Here are two alternatives,
-
Create the cache in
ways_to_make_change()and then pass it toways_to_make_change_helper(), or -
Define
ways_to_make_change_helper()as an inner function ofways_to_make_change(), and then have
the inner function share the cache declared inways_to_make_change().
There was a problem hiding this comment.
Thanks for the suggestions!
I’ve updated the code again based on your guidance. I now create the cache in
ways_to_make_change() and pass it into the helper function, so the cache is scoped
to a single top-level call but shared across all recursive calls.
There was a problem hiding this comment.
Array creation is a relatively costly operation.
From line 34, we know coins can only be one of the following 9 arrays:
[200, 100, 50, 20, 10, 5, 2, 1]
[100, 50, 20, 10, 5, 2, 1]
[50, 20, 10, 5, 2, 1]
...
[1]
We could further improve the performance if we can
- avoid repeatedly creating the same sub-arrays at line 41 (e.g. use another cache), and
- create key as (total, a_unique_integer_identifying_the_subarray) instead of as (total, tuple of coins)
- There are only a small number of different subarrays. We can easily assign each subarray a unique integer.
There was a problem hiding this comment.
Refactor memoisation to avoid repeated sub-array creation
Precompute all possible coin sub-arrays once and identify them by index.
Use (total, subarray_id) as the cache key instead of (total, tuple(coins)),
so recursive calls reuse the same sub-arrays and avoid unnecessary list
and tuple allocations.
|
Looks good. Well done. |
PR summary :
Add manual caching to speed up recursive Fibonacci and ways_to_make_change functions.
fibonacci(n)values to avoid recalculating them.(total, tuple(coins))to remember results for each combination of total and remaining coins.@cache.