Bird
Raised Fist0
DSA Cprogramming~10 mins

DP vs Recursion vs Greedy Choosing the Right Tool in DSA C - Visual Comparison

Choose your learning style10 modes available
Concept Flow - DP vs Recursion vs Greedy Choosing the Right Tool
Start Problem
↓
Can problem be divided into smaller subproblems?
↓
Is there overlapping subproblems?
↓
Use DP (Memoization or Tabulation)
↓
Solve subproblems efficiently
↓
Combine results for final answer
↓
Done
This flow shows how to decide between recursion, dynamic programming, and greedy methods based on problem properties.
Execution Sample
DSA C
int fib(int n) {
  if (n <= 1) return n;
  return fib(n-1) + fib(n-2);
}
Simple recursion to compute Fibonacci number, recalculating subproblems multiple times.
Execution Table
StepOperationNodes in Call StackSubproblem ComputedResult ReturnedVisual State
1Call fib(4)fib(4)None yetPendingCall stack: fib(4)
2Call fib(3)fib(4) -> fib(3)None yetPendingCall stack: fib(4), fib(3)
3Call fib(2)fib(4) -> fib(3) -> fib(2)None yetPendingCall stack: fib(4), fib(3), fib(2)
4Call fib(1)fib(4) -> fib(3) -> fib(2) -> fib(1)fib(1) = 11Return fib(1)=1, pop fib(1)
5Call fib(0)fib(4) -> fib(3) -> fib(2) -> fib(0)fib(0) = 00Return fib(0)=0, pop fib(0)
6Return fib(2) = fib(1)+fib(0)fib(4) -> fib(3)fib(2) = 11Return fib(2)=1, pop fib(2)
7Call fib(1)fib(4) -> fib(3) -> fib(1)fib(1) = 11Return fib(1)=1, pop fib(1)
8Return fib(3) = fib(2)+fib(1)fib(4)fib(3) = 22Return fib(3)=2, pop fib(3)
9Call fib(2)fib(4) -> fib(2)fib(2) recomputedPendingCall stack: fib(4), fib(2)
10Call fib(1)fib(4) -> fib(2) -> fib(1)fib(1) = 11Return fib(1)=1, pop fib(1)
11Call fib(0)fib(4) -> fib(2) -> fib(0)fib(0) = 00Return fib(0)=0, pop fib(0)
12Return fib(2) = fib(1)+fib(0)fib(4)fib(2) = 11Return fib(2)=1, pop fib(2)
13Return fib(4) = fib(3)+fib(2)Nonefib(4) = 33Return fib(4)=3, call stack empty
💡 All recursive calls completed, final result fib(4) = 3 returned
Variable Tracker
VariableStartAfter Step 4After Step 6After Step 8After Step 13
fib(4)Not calledPendingPendingPending3
fib(3)Not calledPending12Returned
fib(2)Not calledPending1Recomputed1
fib(1)Not called1ReturnedReturnedReturned
fib(0)Not called0ReturnedReturnedReturned
Key Moments - 3 Insights
Why does fib(2) get computed twice in simple recursion?
Because recursion calls fib(2) separately from fib(3) and fib(4) without saving results, as shown in steps 6 and 12 in the execution table.
When should we choose dynamic programming over simple recursion?
When subproblems overlap and get recomputed multiple times, like fib(2) here, DP saves results to avoid repeated work, improving efficiency.
Why is greedy not suitable for Fibonacci calculation?
Because Fibonacci depends on previous two values (optimal substructure) but no greedy choice can build the solution step-by-step without missing subproblems.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution table, what is the result returned by fib(3) at step 8?
A1
B2
C3
DPending
💡 Hint
Check the 'Result Returned' column at step 8 in the execution table.
At which step does the call stack become empty, indicating all recursion calls finished?
AStep 10
BStep 12
CStep 13
DStep 6
💡 Hint
Look at the 'Visual State' column for when the call stack is empty.
If we use dynamic programming, how would the number of fib(2) computations change compared to this recursion?
AIt would reduce to one
BIt would increase
CIt would stay the same
DIt would be zero
💡 Hint
Refer to variable_tracker and key_moments about overlapping subproblems.
Concept Snapshot
DP vs Recursion vs Greedy:
- Recursion solves by calling itself, may recompute subproblems.
- DP saves results to avoid repeated work (overlapping subproblems).
- Greedy picks best local choice, works if problem has optimal substructure.
- Choose DP if subproblems overlap.
- Choose Greedy if local choices lead to global optimum.
- Choose Recursion if problem is simple or no overlap.
Full Transcript
This concept helps decide when to use recursion, dynamic programming, or greedy algorithms. Recursion solves problems by calling itself but can repeat work. Dynamic programming improves recursion by saving results of subproblems to avoid recomputation, especially when subproblems overlap. Greedy algorithms pick the best choice at each step and work when this leads to the best overall solution. The example of Fibonacci numbers shows simple recursion calling fib(2) twice, which wastes time. Dynamic programming would compute fib(2) once and reuse it. Greedy is not suitable here because Fibonacci depends on previous two values, not a single local choice. The execution table traces each recursive call and return, showing the call stack growing and shrinking. Variable tracker shows how values change after key steps. Key moments clarify why repeated computation happens and when to choose each method. The visual quiz tests understanding of the execution steps and concepts. This helps beginners see how these approaches differ and when to pick the right tool for a problem.

Practice

(1/5)
1. Which approach is best suited when a problem has 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 problem characteristics

    Overlapping subproblems mean the same smaller problems repeat. Optimal substructure means the best solution can be built from best solutions of smaller problems.
  2. Step 2: Match approach to characteristics

    Dynamic Programming stores results of subproblems to avoid repeated work, ideal for overlapping subproblems and optimal substructure.
  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 optimal substructure with greedy choice property
2. Which of the following is the correct syntax to implement memoization in C for a recursive Fibonacci function?
easy
A. Use a global array to store results and check before recursive calls
B. Use a local variable inside the function to store results
C. Use a static variable without initialization inside the function
D. Use a pointer without allocating memory for memoization

Solution

  1. Step 1: Understand memoization storage

    Memoization requires storing results outside the recursive calls to reuse them. A global or static array is suitable.
  2. Step 2: Check options for correct usage

    Only a global array checked before recursion ensures stored results are reused properly. Local variables reset each call, static without init may cause errors, pointers need allocation.
  3. Final Answer:

    Use a global array to store results and check before recursive calls -> Option A
  4. Quick Check:

    Memoization needs persistent storage = global array [OK]
Hint: Memoize with global/static array checked before recursion [OK]
Common Mistakes:
  • Using local variables that reset each call
  • Not initializing static variables properly
  • Using pointers without memory allocation
3. What will be the output of the following C code snippet implementing a greedy approach for coin change?
int coins[] = {25, 10, 5, 1};
int amount = 30;
int count = 0;
for (int i = 0; i < 4; i++) {
    while (amount >= coins[i]) {
        amount -= coins[i];
        count++;
    }
}
printf("%d\n", count);
medium
A. 3
B. 2
C. 4
D. 5

Solution

  1. Step 1: Trace the greedy coin selection

    Start with 30 amount. Use 25 coin once (30-25=5), count=1. Then 10 coin can't be used (5<10). Use 5 coin once (5-5=0), count=2.
  2. Step 2: Count total coins used

    Coins used: 25 (1), 5 (1), total count = 2 coins. The code increments count inside while loop, so count=2.
  3. Step 3: Check for remaining coins

    Amount is now 0, so no more coins used.
  4. Final Answer:

    2 -> Option B
  5. Quick Check:

    Greedy coin count for 30 = 2 coins [OK]
Hint: Subtract largest coin repeatedly until amount zero [OK]
Common Mistakes:
  • Counting coins incorrectly by missing loops
  • Assuming greedy always gives minimum coins
  • Confusing coin values and counts
4. Identify the error in this recursive function for factorial and suggest the fix:
int factorial(int n) {
    if (n == 0) return 0;
    return n * factorial(n - 1);
}
medium
A. Recursive call should be factorial(n + 1)
B. Function should return void
C. Base case should return 1 instead of 0
D. No error, code is correct

Solution

  1. Step 1: Analyze base case correctness

    Factorial of 0 is 1, but code returns 0, which will cause all results to be zero.
  2. Step 2: Suggest correct base case

    Change base case to return 1 when n == 0 to correctly end recursion and compute factorial.
  3. Final Answer:

    Base case should return 1 instead of 0 -> Option C
  4. Quick Check:

    Factorial(0) = 1 base case [OK]
Hint: Factorial base case returns 1, not 0 [OK]
Common Mistakes:
  • Returning 0 in base case causing zero product
  • Changing recursion direction incorrectly
  • Ignoring base case leading to infinite recursion
5. You want to find the minimum number of coins to make a given amount using coins of denominations {1, 3, 4}. Which approach is best and why?
hard
A. Brute force, to try all combinations without optimization
B. Recursion without memoization, to explore all possibilities
C. Greedy, because always picking largest coin works
D. Dynamic Programming, to store and reuse subproblem results

Solution

  1. Step 1: Understand problem requirements

    Minimum coins for amount with coins {1,3,4} needs checking all combinations to find optimal solution.
  2. Step 2: Evaluate approaches

    Greedy fails here because picking largest coin first may not yield minimum coins. Recursion without memoization is slow. Dynamic Programming stores results of smaller amounts to build optimal solution efficiently.
  3. Final Answer:

    Dynamic Programming, to store and reuse subproblem results -> Option D
  4. Quick Check:

    Minimum coins with overlapping subproblems = DP [OK]
Hint: Use DP when greedy fails to find minimum coins [OK]
Common Mistakes:
  • Assuming greedy always works for coin change
  • Using recursion without memo causing slow code
  • Ignoring overlapping subproblems in coin change
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