📖 Scenario: You are helping a friend who wants to find the number of ways to climb stairs. Each time, they can climb either 1 or 2 steps. They want to know how many different ways they can reach the top if the staircase has a certain number of steps.
🎯 Goal: Build a program using memoization (top-down dynamic programming) to efficiently calculate the number of ways to climb a staircase with n steps.
📋 What You'll Learn
Create a function called climbStairs that takes a number n as input.
Use a memo object called memo to store results of subproblems.
Implement the recursive logic with memoization to avoid repeated calculations.
Print the number of ways to climb n steps.
💡 Why This Matters
🌍 Real World
Calculating ways to climb stairs is a classic example of counting problems in real life, such as counting paths, combinations, or sequences.
💼 Career
Memoization and dynamic programming are important skills for software engineers to optimize recursive algorithms and improve performance in coding interviews and real projects.
Progress0 / 4 steps
1
Create the memo object
Create an empty object called memo to store previously calculated results.
DSA Typescript
Hint
Use const memo: { [key: number]: number } = {}; to create an empty object for memoization.
2
Create the climbStairs function
Create a function called climbStairs that takes a number n as input.
DSA Typescript
Hint
Define the function with function climbStairs(n: number): number {}.
3
Add memoization and recursive logic
Inside climbStairs, add these steps: 1. If n is 0 or 1, return 1. 2. If memo[n] exists, return memo[n]. 3. Otherwise, calculate climbStairs(n - 1) + climbStairs(n - 2), store it in memo[n], and return it.
DSA Typescript
Hint
Use base cases for 0 and 1 steps, check memo before recursion, and store results in memo.
4
Print the result for n = 5
Call climbStairs with n = 5 and print the result using console.log.
DSA Typescript
Hint
Use console.log(climbStairs(5)); to print the number of ways.
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
Step 1: Understand memoization concept
Memoization saves the results of subproblems so they are not recalculated.
Step 2: Compare options
Only To store results of subproblems to avoid repeated calculations correctly describes this purpose; others describe unrelated actions.
Final Answer:
To store results of subproblems to avoid repeated calculations -> Option D
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
Step 1: Identify memo type for number keys and values
Memo should map number keys to number values, so Record fits.
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.
Final Answer:
const memo: Record = {}; -> Option A
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));
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
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.
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.
Final Answer:
It incorrectly checks memo[n] which fails for factorial(0) -> Option A
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
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.
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.
Final Answer:
Option C correctly applies memoization with proper cache check -> Option C
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 unknownstrongwhile earning +1 Grip toward your certificate.