London | 25-SDC-Nov | Aida Eslamimoghadam | Sprint 2 | Add caching to improve performance#144
London | 25-SDC-Nov | Aida Eslamimoghadam | Sprint 2 | Add caching to improve performance#144aydaeslami wants to merge 2 commits into
Conversation
| @@ -26,7 +27,11 @@ def ways_to_make_change_helper(total: int, coins: List[int]) -> int: | |||
| if total_from_coins == total: | |||
| ways += 1 | |||
| else: | |||
| intermediate = ways_to_make_change_helper(total - total_from_coins, coins=coins[coin_index+1:]) | |||
| ways += intermediate | |||
| ways += ways_to_make_change_helper( | |||
| total - total_from_coins, | |||
| coins=coins[coin_index + 1:] | |||
| ) | |||
There was a problem hiding this comment.
Array and tuple creations are relatively costly operations.
From lines 6 and 32, 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 32 (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.
|
Thanks a million @cjyuan for your suggestion, I updated the solution to use start_index instead of creating coin sub-arrays, and changed the cache key to total, start_index to avoid unnecessary array and tuple creation. |
| def ways_to_make_change_helper(total: int, coins: List[int]) -> int: | ||
| key = (total, tuple(coins)) | ||
| def ways_to_make_change_helper(total: int, start_index: int) -> int: | ||
| key = (total, start_index) |
There was a problem hiding this comment.
Why not pass the coin list through the parameter (in addition to passing start_index) so that the function can be reused for different coin list?
When we pass a list to a function, we are only passing its reference -- the cost is negligible.
| ways = 0 | ||
| for coin_index in range(len(coins)): | ||
| coin = coins[coin_index] | ||
| for coin_index in range(start_index, len(COINS)): |
There was a problem hiding this comment.
This loop is actually redundant. Subsequent coins will be considered in the recursive function calls anyway.
Self checklist
Changelist
Added caching (memoisation) to avoid repeated calculations and improve performance of recursive functions.