Why Dynamic Programming and When Recursion Alone Fails
📖 Scenario: Imagine you want to find the number of ways to climb a staircase with 5 steps. You can take either 1 step or 2 steps at a time. This is a classic problem where recursion alone can be slow because it repeats the same calculations many times. Dynamic Programming helps us solve this efficiently by remembering past results.
🎯 Goal: You will build a Go program that first uses simple recursion to count ways to climb stairs, then add a memory helper to avoid repeated work, showing why dynamic programming is better.
📋 What You'll Learn
Create a recursive function to count ways to climb stairs
Add a map to remember results for each step count
Modify the recursive function to use the map for faster results
Print the number of ways to climb 5 steps using both methods
💡 Why This Matters
🌍 Real World
Counting ways to climb stairs models many problems like counting paths, sequences, or combinations where overlapping subproblems occur.
💼 Career
Understanding dynamic programming is essential for software engineers to write efficient algorithms and solve complex problems in interviews and real projects.
Progress0 / 4 steps
1
Create a recursive function to count ways to climb stairs
Write a recursive function called countWays that takes an integer n representing steps left and returns the number of ways to climb those steps. Use the rule: if n is 0 or 1, return 1; otherwise, return countWays(n-1) + countWays(n-2). Then call countWays(5) and store the result in a variable called waysRecursive.
DSA Go
Hint
Think of the base cases when steps left are 0 or 1. For other cases, add results of smaller problems.
2
Add a map to remember results for each step count
Create a map called memo of type map[int]int to store previously calculated results for each number of steps. Initialize it as an empty map in main.
DSA Go
Hint
Use make(map[int]int) to create an empty map for memoization.
3
Modify the recursive function to use the map for faster results
Change the countWays function to take a second parameter memo map[int]int. Before computing, check if n is in memo. If yes, return the stored value. Otherwise, compute the result recursively, store it in memo[n], and return it. Update the call in main to pass memo.
DSA Go
Hint
Use the map to check if the answer is already known before computing.
4
Print the number of ways to climb 5 steps using both methods
In main, call the original recursive function countWaysSimple (which you will create as a copy of the original countWays without memo) with 5 steps and store in waysSimple. Then call the memoized countWays with 5 steps and memo and store in waysMemo. Finally, print both results with labels "Ways with simple recursion:" and "Ways with memoization:".
DSA Go
Hint
Print the results using fmt.Println with clear labels.
Practice
(1/5)
1. Why do we use dynamic programming instead of plain recursion for some problems?
easy
A. Because dynamic programming uses less memory than recursion
B. Because dynamic programming stores results to avoid repeated work
C. Because recursion cannot solve problems with multiple choices
D. Because recursion is always slower than loops
Solution
Step 1: Understand recursion's limitation
Recursion often recalculates the same subproblems multiple times, causing inefficiency.
Step 2: Role of dynamic programming
Dynamic programming saves results of subproblems (memoization) to avoid repeated calculations.
Final Answer:
Because dynamic programming stores results to avoid repeated work -> Option B
Quick Check:
Memoization avoids repeated work = D [OK]
Hint: Dynamic programming saves repeated results to speed up recursion [OK]
Common Mistakes:
Thinking recursion is always slower than loops
Believing recursion can't handle multiple choices
Confusing memory use between recursion and DP
2. Which Go syntax correctly declares a recursive function to compute Fibonacci numbers?
easy
A. func fib(n int) int { if n <= 1 { return n } return fib(n-1) + fib(n-2) }
B. func fib(n int) { if n <= 1 { return n } return fib(n-1) + fib(n-2) }
C. func fib(n int) int { if n < 0 { return 0 } return fib(n-1) + fib(n-2) }
D. func fib(n int) int { if n == 0 { return 0 } else { return fib(n-1) + fib(n-2) } }
Solution
Step 1: Check function signature and return type
func fib(n int) int { if n <= 1 { return n } return fib(n-1) + fib(n-2) } correctly declares return type int and returns int values.
Step 2: Verify base cases and recursion
func fib(n int) int { if n <= 1 { return n } return fib(n-1) + fib(n-2) } uses base case n <= 1 returning n, and recursive calls fib(n-1)+fib(n-2), which is correct.
Final Answer:
func fib(n int) int { if n <= 1 { return n } return fib(n-1) + fib(n-2) } -> Option A
Quick Check:
Correct signature and base case = B [OK]
Hint: Check function return type and base cases carefully [OK]
Common Mistakes:
Missing return type in function signature
Incorrect base case conditions
Returning void instead of int
3. What is the output of this Go code snippet?
import "fmt"
func fib(n int) int {
if n <= 1 {
return n
}
return fib(n-1) + fib(n-2)
}
func main() {
fmt.Println(fib(5))
}