Bird
Raised Fist0
DSA Typescriptprogramming~20 mins

DP vs Recursion vs Greedy Choosing the Right Tool in DSA Typescript - Compare & Choose

Choose your learning style10 modes available
Challenge - 5 Problems
🎖️
DP vs Recursion vs Greedy Master
Get all challenges correct to earn this badge!
Test your skills under time pressure!
❓ Predict Output
intermediate
2:00remaining
Output of Recursive Fibonacci Function
What is the output of the following TypeScript code that uses recursion to calculate Fibonacci numbers?
DSA Typescript
function fib(n: number): number {
  if (n <= 1) return n;
  return fib(n - 1) + fib(n - 2);
}
console.log(fib(5));
A3
B8
C13
D5
Attempts:
2 left
💡 Hint
Trace the recursive calls for fib(5).
🧠 Conceptual
intermediate
1:30remaining
Choosing Greedy vs Dynamic Programming
Which problem characteristic best indicates that a greedy algorithm is the right choice over dynamic programming?
AOptimal substructure without overlapping subproblems
BNo optimal substructure
COptimal substructure and overlapping subproblems
DOverlapping subproblems without optimal substructure
Attempts:
2 left
💡 Hint
Greedy algorithms work when local choices lead to global optimum.
🔧 Debug
advanced
2:00remaining
Why Does This Memoized Recursive Code Fail?
Consider this TypeScript code for memoized recursion to compute factorial. What error does it produce?
DSA Typescript
function factorial(n: number, memo: {[key: number]: number} = {}): number {
  if (n <= 1) return 1;
  if (memo[n]) return memo[n];
  memo[n] = n * factorial(n - 1, memo);
  return memo[n];
}
console.log(factorial(0));
AReturns 1
BStack overflow error
CTypeError: Cannot read property of undefined
DReturns undefined
Attempts:
2 left
💡 Hint
Check base case for n=0.
❓ Predict Output
advanced
2:00remaining
Output of Greedy Coin Change Algorithm
What is the output of this TypeScript code that uses a greedy approach to make change for 30 cents with coins [25, 10, 5, 1]?
DSA Typescript
function greedyChange(coins: number[], amount: number): number[] {
  const result: number[] = [];
  for (const coin of coins) {
    while (amount >= coin) {
      amount -= coin;
      result.push(coin);
    }
  }
  return result;
}
console.log(greedyChange([25, 10, 5, 1], 30));
A[5, 5, 5, 5, 5, 5]
B[25, 5]
C[25, 1, 1, 1, 1, 1]
D[10, 10, 10]
Attempts:
2 left
💡 Hint
Greedy picks largest coin first.
🧠 Conceptual
expert
2:30remaining
When Is Dynamic Programming Necessary Over Greedy?
Which scenario best explains when dynamic programming is necessary instead of a greedy approach?
AWhen local optimal choices always lead to global optimum
BWhen the problem has optimal substructure but no overlapping subproblems
CWhen the problem has optimal substructure and overlapping subproblems requiring exploration of all subproblems
DWhen the problem has no optimal substructure
Attempts:
2 left
💡 Hint
Dynamic programming solves overlapping subproblems efficiently.

Practice

(1/5)
1. Which approach is best when a problem can be broken into overlapping subproblems and optimal substructure?
easy
A. Dynamic Programming
B. Greedy Algorithm
C. Simple Recursion without memoization
D. Brute Force

Solution

  1. Step 1: Understand overlapping subproblems

    Dynamic Programming works well when subproblems repeat and can be reused.
  2. Step 2: Check optimal substructure property

    Dynamic Programming uses optimal solutions of subproblems to build the final solution.
  3. Final Answer:

    Dynamic Programming -> Option A
  4. Quick Check:

    Overlapping subproblems + optimal substructure = Dynamic Programming [OK]
Hint: Use DP when subproblems repeat and build optimal solutions [OK]
Common Mistakes:
  • Choosing greedy when subproblems overlap
  • Using simple recursion without memoization causing slow code
  • Confusing brute force with DP
2. Which of the following TypeScript function signatures correctly implements a recursive Fibonacci function?
easy
A. function fib(n: number): number { return n <= 1 ? n : fib(n-1) + fib(n-2); }
B. function fib(n: number): number { let a = 0; let b = 1; for(let i=2; i<=n; i++) { let c = a + b; a = b; b = c; } return b; }
C. function fib(n: number): number { return n + fib(n-1); }
D. function fib(n: number): number { if(n == 0) return 0; else return fib(n-1) * fib(n-2); }

Solution

  1. Step 1: Check base case correctness

    function fib(n: number): number { return n <= 1 ? n : fib(n-1) + fib(n-2); } returns n if n <= 1, which correctly handles fib(0)=0 and fib(1)=1.
  2. Step 2: Check recursive calls

    function fib(n: number): number { return n <= 1 ? n : fib(n-1) + fib(n-2); } calls fib(n-1) + fib(n-2), matching Fibonacci definition.
  3. Final Answer:

    function fib(n: number): number { return n <= 1 ? n : fib(n-1) + fib(n-2); } -> Option A
  4. Quick Check:

    Correct base case and recursive sum = function fib(n: number): number { return n <= 1 ? n : fib(n-1) + fib(n-2); } [OK]
Hint: Base case n<=1 and sum of fib(n-1)+fib(n-2) is key [OK]
Common Mistakes:
  • Missing base case causing infinite recursion
  • Using multiplication instead of addition
  • Incorrect loop instead of recursion
3. What is the output of the following TypeScript code using recursion to calculate factorial?
function factorial(n: number): number {
  if (n === 0) return 1;
  return n * factorial(n - 1);
}
console.log(factorial(4));
medium
A. 10
B. Error
C. 120
D. 24

Solution

  1. Step 1: Trace recursive calls for factorial(4)

    factorial(4) = 4 * factorial(3), factorial(3) = 3 * factorial(2), factorial(2) = 2 * factorial(1), factorial(1) = 1 * factorial(0), factorial(0) = 1.
  2. Step 2: Calculate values bottom-up

    factorial(0) = 1, factorial(1) = 1*1=1, factorial(2) = 2*1=2, factorial(3) = 3*2=6, factorial(4) = 4*6=24.
  3. Final Answer:

    24 -> Option D
  4. Quick Check:

    4! = 24 [OK]
Hint: Factorial n! = n*(n-1)! with base 0! = 1 [OK]
Common Mistakes:
  • Confusing factorial with sum
  • Missing base case causing stack overflow
  • Incorrect multiplication order
4. The following greedy algorithm tries to find the minimum number of coins for a given amount. What is the bug?
function minCoins(coins: number[], amount: number): number {
  coins.sort((a, b) => b - a);
  let count = 0;
  for (let coin of coins) {
    count += Math.floor(amount / coin);
    amount %= coin;
  }
  return count;
}
console.log(minCoins([1, 3, 4], 6));
medium
A. Sorting coins ascending instead of descending
B. Greedy fails for coin sets where local choice isn't optimal
C. Using floor division instead of ceil
D. Not handling zero amount input

Solution

  1. Step 1: Understand greedy approach for coin change

    Greedy picks largest coin first, but it may not yield minimum coins for all coin sets.
  2. Step 2: Check example with coins [1,3,4] and amount 6

    Greedy picks 4 once, then 1 twice = 3 coins; but optimal is 3+3 = 2 coins.
  3. Final Answer:

    Greedy fails for coin sets where local choice isn't optimal -> Option B
  4. Quick Check:

    Greedy not always optimal for coin change [OK]
Hint: Greedy fails if local best choice isn't globally best [OK]
Common Mistakes:
  • Assuming greedy always works for coin change
  • Ignoring coin sorting order
  • Confusing floor and ceil division
5. You want to find the longest increasing subsequence (LIS) in an array. Which approach is best and why?
const arr = [10, 9, 2, 5, 3, 7, 101, 18];
hard
A. Greedy, because picking local max always gives LIS
B. Recursion without memoization, to explore all subsequences
C. Dynamic Programming, to store LIS lengths and build solution efficiently
D. Brute force, checking all subsequences

Solution

  1. Step 1: Analyze problem characteristics

    LIS requires checking many subsequences with overlapping subproblems and optimal substructure.
  2. Step 2: Choose approach with efficiency

    Dynamic Programming stores LIS lengths for subproblems, avoiding repeated work and improving speed.
  3. Final Answer:

    Dynamic Programming, to store LIS lengths and build solution efficiently -> Option C
  4. Quick Check:

    LIS best solved by DP due to overlapping subproblems [OK]
Hint: Use DP for LIS to avoid exponential recursion [OK]
Common Mistakes:
  • Using greedy which fails for LIS
  • Recursion without memoization causing slow code
  • Trying brute force which is inefficient
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