Memoization Top Down DP in DSA Javascript - Time & Space Complexity
We want to understand how using memoization changes the time it takes to solve problems with repeated calculations.
How does saving results help reduce repeated work?
Analyze the time complexity of the following memoized Fibonacci function.
function fib(n, memo = {}) {
if (n <= 1) return n;
if (memo[n] !== undefined) return memo[n];
memo[n] = fib(n - 1, memo) + fib(n - 2, memo);
return memo[n];
}
This function calculates the nth Fibonacci number using memoization to save results of smaller problems.
Look at the recursive calls and how many times each happens.
- Primary operation: Recursive calls to fib with smaller n.
- How many times: Each unique n from 0 to n is computed once and saved.
Each number from 0 up to n is calculated once, so the work grows roughly in a straight line with n.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 calculations |
| 100 | About 100 calculations |
| 1000 | About 1000 calculations |
Pattern observation: Doubling n roughly doubles the work, showing linear growth.
Time Complexity: O(n)
This means the time to compute grows in a straight line with the input size because each subproblem is solved once.
[X] Wrong: "Memoization still causes exponential time because of recursion."
[OK] Correct: Memoization saves results so each input is computed once, avoiding repeated work and reducing time to linear.
Understanding memoization shows you how to turn slow recursive solutions into fast ones, a key skill for many coding challenges.
"What if we removed memoization and just used plain recursion? How would the time complexity change?"
Practice
Solution
Step 1: Understand memoization concept
Memoization saves the results of expensive function calls and returns the cached result when the same inputs occur again.Step 2: Identify its role in top-down DP
In top-down dynamic programming, memoization prevents repeated calculations of the same subproblems by storing their results.Final Answer:
To store results of subproblems to avoid repeated calculations -> Option AQuick Check:
Memoization = Store subproblem results [OK]
- Confusing memoization with sorting
- Thinking memoization reduces memory usage
- Believing memoization converts recursion to iteration
Solution
Step 1: Identify memo storage type
Memoization requires a data structure to store key-value pairs of subproblem results. Map is ideal for this in JavaScript.Step 2: Check options for correct syntax
const memo = new Map(); usesnew Map()which is correct. let memo = []; is an array, which can work but less flexible. var memo = function() {}; is a function, incorrect. const memo = 0; is a number, incorrect.Final Answer:
const memo = new Map(); -> Option CQuick Check:
Memo object = Map() [OK]
- Using a function instead of an object
- Initializing memo as a number
- Confusing array with Map for memo
const memo = new Map();
function fib(n) {
if (n <= 1) return n;
if (memo.has(n)) return memo.get(n);
const result = fib(n - 1) + fib(n - 2);
memo.set(n, result);
return result;
}
console.log(fib(5));Solution
Step 1: Understand Fibonacci sequence
Fibonacci sequence starts as 0,1,1,2,3,5,8,... So fib(5) = 5.Step 2: Trace the code execution
The function uses memoization to avoid repeated calls. fib(5) calculates fib(4)+fib(3), and so on, finally returning 5.Final Answer:
5 -> Option AQuick Check:
fib(5) = 5 [OK]
- Confusing fib(5) with fib(6)
- Ignoring base cases
- Not understanding memo usage
const memo = {};
function factorial(n) {
if (n === 0) return 1;
if (memo[n]) return memo[n];
memo[n] = n * factorial(n - 1);
return memo[n];
}
console.log(factorial(5));Solution
Step 1: Understand the bug in memo check
Using 'if (memo[n])' fails when memo[n] is 0 or falsy. It should check if the key exists.Step 2: Fix by checking key existence
Using 'memo.hasOwnProperty(n)' correctly checks if the result is stored, avoiding false negatives.Final Answer:
Change 'if (memo[n])' to 'if (memo.hasOwnProperty(n))' -> Option BQuick Check:
Check key existence, not truthiness [OK]
- Checking memo[n] directly causes bugs for 0 or falsy values
- Changing base case unnecessarily
- Removing memo defeats purpose
countWays(4)? const memo = {};
function countWays(n) {
if (n === 0) return 1;
if (n < 0) return 0;
if (memo.hasOwnProperty(n)) return memo[n];
memo[n] = countWays(n - 1) + countWays(n - 2);
return memo[n];
}
console.log(countWays(4));Solution
Step 1: Understand the problem
This function counts ways to climb stairs taking 1 or 2 steps. Base cases: countWays(0)=1, countWays(negative)=0.Step 2: Calculate countWays(4) step-by-step
countWays(4) = countWays(3) + countWays(2) countWays(3) = countWays(2) + countWays(1) countWays(2) = countWays(1) + countWays(0) countWays(1) = countWays(0) + countWays(-1) countWays(0) = 1, countWays(-1) = 0 So countWays(1) = 1 + 0 = 1 countWays(2) = 1 + 1 = 2 countWays(3) = 2 + 1 = 3 countWays(4) = 3 + 2 = 5Final Answer:
5 -> Option DQuick Check:
Ways to climb 4 stairs = 5 [OK]
- Miscounting base cases
- Forgetting negative input returns 0
- Mixing up addition order
Ready to prove it?
Pass the test and this pattern moves unknown
