Bird
Raised Fist0
DSA Typescriptprogramming~10 mins

Memoization Top Down DP in DSA Typescript - Execution Trace

Choose your learning style10 modes available
Concept Flow - Memoization Top Down DP
Start with problem input
↓
Check if result in memo?
Yes→Return memoized result
No↓
Compute result recursively
↓
Store result in memo
↓
Return computed result
The flow starts by checking if the answer is already saved (memo). If yes, return it. If no, compute recursively, save it, then return.
Execution Sample
DSA Typescript
function fib(n: number, memo: number[] = []): number {
  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];
}
Calculates Fibonacci number n using top-down memoization to avoid repeated work.
Execution Table
StepOperationnMemo BeforeRecursive CallsMemo AfterReturned Value
1fib(4) called4[]fib(3), fib(2)[empty]pending
2fib(3) called3[]fib(2), fib(1)[empty]pending
3fib(2) called2[]fib(1), fib(0)[empty]pending
4fib(1) base case1[]none[empty]1
5fib(0) base case0[]none[empty]0
6fib(2) computed2[]fib(1)=1, fib(0)=0[, , 1]1
7fib(1) base case1[, , 1]none[, , 1]1
8fib(3) computed3[, , 1]fib(2)=1, fib(1)=1[, , 1, 2]2
9fib(2) memo hit2[, , 1, 2]none[, , 1, 2]1
10fib(4) computed4[, , 1, 2]fib(3)=2, fib(2)=1[, , 1, 2, 3]3
11Return final result4[, , 1, 2, 3]none[, , 1, 2, 3]3
💡 All recursive calls resolved and memo filled; final result fib(4) = 3 returned.
Variable Tracker
VariableStartAfter Step 6After Step 8After Step 10Final
n42344
memo[][, , 1][, , 1, 2][, , 1, 2, 3][, , 1, 2, 3]
Returned Valuepending1233
Key Moments - 3 Insights
Why do we check if memo[n] is defined before computing?
Because if memo[n] exists, it means we already computed fib(n). We return it immediately to avoid repeating work, as shown in steps 9 and 10 where fib(2) is returned from memo.
What happens when n is 0 or 1?
These are base cases that return n directly without recursion, as in steps 4 and 5. This stops infinite recursion and starts building answers up.
How does memoization reduce the number of recursive calls?
Memoization saves results so repeated calls like fib(2) in step 9 return instantly from memo instead of recomputing, drastically reducing calls.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution table at step 6. What is the memo array after computing fib(2)?
A[, , 2]
B[, , 1]
C[1, 1]
D[]
💡 Hint
Check the 'Memo After' column at step 6 in the execution table.
At which step does the function return the final result for fib(4)?
AStep 8
BStep 10
CStep 11
DStep 9
💡 Hint
Look for the step where 'Returned Value' is 3 and no further recursive calls happen.
If memoization was not used, how would the number of recursive calls change?
AThey would increase because repeated calls are not cached.
BThey would decrease because memoization adds overhead.
CThey would stay the same.
DThey would stop immediately.
💡 Hint
Refer to the 'Recursive Calls' column and how memo hits avoid calls.
Concept Snapshot
Memoization Top Down DP:
- Use recursion with a memo (cache) to save results.
- Check memo before computing to avoid repeats.
- Base cases return direct answers.
- Store computed results in memo.
- Return memoized or computed result.
- Greatly reduces repeated work in overlapping subproblems.
Full Transcript
Memoization in top-down dynamic programming means saving results of recursive calls in a memo array. When the function is called with a parameter n, it first checks if the answer is already in memo. If yes, it returns that answer immediately. If not, it computes the answer recursively, stores it in memo, and returns it. Base cases like n=0 or n=1 return immediately without recursion. This approach avoids repeated calculations of the same subproblems, making the algorithm efficient. The example traced is Fibonacci number calculation for n=4, showing how memo fills step-by-step and recursive calls reduce.

Practice

(1/5)
1. What is the main purpose of memoization in top-down dynamic programming?
easy
A. To reduce the memory usage by deleting variables
B. To sort the input data before processing
C. To convert recursive code into iterative code
D. To store results of subproblems to avoid repeated calculations

Solution

  1. Step 1: Understand memoization concept

    Memoization saves the results of subproblems so they are not recalculated.
  2. Step 2: Compare options

    Only To store results of subproblems to avoid repeated calculations correctly describes this purpose; others describe unrelated actions.
  3. Final Answer:

    To store results of subproblems to avoid repeated calculations -> Option D
  4. Quick Check:

    Memoization = store subproblem results [OK]
Hint: Memoization caches answers to reuse later [OK]
Common Mistakes:
  • Confusing memoization with sorting
  • Thinking memoization reduces memory by deleting variables
  • Believing memoization converts recursion to iteration
2. Which of the following is the correct TypeScript syntax to declare a memo object for caching number results indexed by number keys?
easy
A. const memo: Record = {};
B. const memo: Array<number> = [];
C. const memo: Map = new Map();
D. const memo: Set<number> = new Set();

Solution

  1. Step 1: Identify memo type for number keys and values

    Memo should map number keys to number values, so Record fits.
  2. Step 2: Check other options

    Array is indexed by number but not key-value pairs; Map uses string keys here; Set stores unique values, not key-value pairs.
  3. Final Answer:

    const memo: Record = {}; -> Option A
  4. Quick Check:

    Memo object with number keys and values = Record [OK]
Hint: Use Record for number-keyed memo objects [OK]
Common Mistakes:
  • Using Map with wrong key/value types
  • Using Set which stores only values, not key-value pairs
  • Using Array when keys are not continuous indexes
3. Consider the following TypeScript code using memoization for Fibonacci numbers:
function fib(n: number, memo: Record = {}): number {
  if (n <= 1) return n;
  if (memo[n]) return memo[n];
  memo[n] = fib(n - 1, memo) + fib(n - 2, memo);
  return memo[n];
}
console.log(fib(5));

What is the output of this code?
medium
A. Undefined
B. 5
C. 3
D. 8

Solution

  1. Step 1: Trace fib(5) calls with memoization

    fib(5) = fib(4) + fib(3), fib(4) = fib(3) + fib(2), fib(3) = fib(2) + fib(1), fib(2) = fib(1) + fib(0). Values: fib(0)=0, fib(1)=1.
  2. Step 2: Calculate values bottom-up

    fib(2)=1, fib(3)=2, fib(4)=3, fib(5)=5.
  3. Final Answer:

    5 -> Option B
  4. Quick Check:

    fib(5) = 5 [OK]
Hint: Remember fib(5) = 5 in Fibonacci sequence [OK]
Common Mistakes:
  • Confusing fib(5) with fib(6)
  • Forgetting base cases fib(0)=0 and fib(1)=1
  • Assuming memo[n] is undefined for n=1
4. The following TypeScript function attempts to use memoization for factorial calculation but has a bug:
function factorial(n: number, memo: Record = {}): number {
  if (n === 0) return 1;
  if (memo[n]) return memo[n];
  memo[n] = n * factorial(n - 1, memo);
  return memo[n];
}

What is the bug in this code?
medium
A. It incorrectly checks memo[n] which fails for factorial(0)
B. It does not handle the base case correctly
C. It uses the wrong multiplication operator
D. It does not pass memo object in recursive calls

Solution

  1. Step 1: Analyze memo[n] check for zero value

    When n=0, factorial is 1, but memo[0] is undefined initially. The check if(memo[n]) fails for memo[0] = 0 or 1 because 0 or 1 are falsy/truthy but memo[0] might be undefined.
  2. Step 2: Identify correct memo check

    Checking if(memo[n]) fails if memo[n] is 0 or falsy. Should check if(n in memo) instead to detect cached values correctly.
  3. Final Answer:

    It incorrectly checks memo[n] which fails for factorial(0) -> Option A
  4. Quick Check:

    Check memo keys with 'in' operator, not truthy check [OK]
Hint: Use 'n in memo' to check cache, not 'if(memo[n])' [OK]
Common Mistakes:
  • Assuming memo[n] check works for zero or falsy values
  • Missing base case for n=0
  • Not passing memo in recursive calls
5. You want to optimize a function that counts the number of ways to climb n stairs taking 1 or 2 steps at a time using top-down memoization. Which of the following TypeScript implementations correctly applies memoization to avoid repeated calculations?
hard
A. function climbStairs(n: number, memo: Record = {}): number { if (n <= 1) return 1; if (memo[n]) return memo[n]; memo[n] = climbStairs(n - 1, memo) + climbStairs(n - 2, memo); return memo[n]; }
B. function climbStairs(n: number): number { if (n <= 1) return 1; return climbStairs(n - 1) + climbStairs(n - 2); }
C. function climbStairs(n: number, memo: Record = {}): number { if (n <= 1) return 1; if (memo[n] !== undefined) return memo[n]; memo[n] = climbStairs(n - 1, memo) + climbStairs(n - 2, memo); return memo[n]; }
D. function climbStairs(n: number, memo: Record = {}): number { if (n <= 1) return 1; if (memo[n] === 0) return memo[n]; memo[n] = climbStairs(n - 1, memo) + climbStairs(n - 2, memo); return memo[n]; }

Solution

  1. Step 1: Check memoization condition correctness

    function climbStairs(n: number, memo: Record = {}): number { if (n <= 1) return 1; if (memo[n] !== undefined) return memo[n]; memo[n] = climbStairs(n - 1, memo) + climbStairs(n - 2, memo); return memo[n]; } uses 'memo[n] !== undefined' to check cache, which correctly handles zero or falsy values.
  2. Step 2: Compare other options

    function climbStairs(n: number, memo: Record = {}): number { if (n <= 1) return 1; if (memo[n]) return memo[n]; memo[n] = climbStairs(n - 1, memo) + climbStairs(n - 2, memo); return memo[n]; } uses 'if(memo[n])' which fails if memo[n] is 0; function climbStairs(n: number): number { if (n <= 1) return 1; return climbStairs(n - 1) + climbStairs(n - 2); } has no memoization; function climbStairs(n: number, memo: Record = {}): number { if (n <= 1) return 1; if (memo[n] === 0) return memo[n]; memo[n] = climbStairs(n - 1, memo) + climbStairs(n - 2, memo); return memo[n]; } checks 'memo[n] === 0' which misses other cached values.
  3. Final Answer:

    Option C correctly applies memoization with proper cache check -> Option C
  4. Quick Check:

    Use '!== undefined' to check memo cache [OK]
Hint: Check cache with '!== undefined' to handle all values [OK]
Common Mistakes:
  • Using 'if(memo[n])' which fails for zero values
  • Not passing memo in recursive calls
  • Not using memoization at all
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard