|
| 1 | +# Changes Made: Optimization via Memoisation |
| 2 | + |
| 3 | +## Overview |
| 4 | +The goal of these changes was to improve the performance of recursive functions that were previously performing redundant calculations. By introducing a manual cache (memoisation), the time complexity was reduced from exponential to linear. |
| 5 | + |
| 6 | +## 1. Fibonacci Optimization (`fibonacci.py`) |
| 7 | +- **Implemented Memoisation**: Introduced a dictionary named `memo` to store the results of each Fibonacci term as it is calculated. |
| 8 | +- **Improved Complexity**: |
| 9 | + - **Before**: $O(2^n)$ (Exponential) - The function recalculated the same branches of the recursion tree millions of times. |
| 10 | + - **After**: $O(n)$ (Linear) - Each term is calculated exactly once and then retrieved from the cache. |
| 11 | +- **Readability**: Renamed the parameter `n` to `term_index` to more clearly describe that the function is looking for a specific position in a sequence. |
| 12 | + |
| 13 | +## 2. Making Change Optimization (`making_change.py`) |
| 14 | +- **Recursive Helper Pattern**: Refactored the original iterative-recursive logic into a dedicated helper function (`ways_to_make_change_helper`) to better support memoisation. |
| 15 | +- **State Tracking**: |
| 16 | + - Created a **state key** using a Tuple: `(total, len(coins))`. |
| 17 | + - **The "Why"**: A unique solution depends on both the amount of money left and which coins are still available. A tuple is used because it is immutable and can be used as a dictionary key. |
| 18 | +- **Logic Refinement**: |
| 19 | + - Updated the base case to return `1` when `total == 0`, representing a successful combination. |
| 20 | + - Added `memo.clear()` in the wrapper function to ensure the cache is fresh for every new call to the main function. |
| 21 | +- **Legacy Preservation**: Maintained original variable names (`coin`, `count_of_coin`, `intermediate`) while implementing the performance improvements. |
| 22 | + |
| 23 | +## 3. Technical Trade-offs: Space vs. Time |
| 24 | +In both implementations, I applied the **Space-vs-Time trade-off**: |
| 25 | +- **The Cost (Space)**: Increased memory usage to store the `memo` dictionary. |
| 26 | +- **The Benefit (Time)**: Drastic reduction in execution time. For example, `ways_to_make_change(9176)` now returns a result instantly, whereas the unoptimised version would likely never finish on standard hardware. |
0 commit comments