Fibonacci Using DP in DSA Go - Time & Space Complexity
We want to understand how fast the Fibonacci sequence calculation using dynamic programming runs.
How does the time needed grow as we ask for bigger Fibonacci numbers?
Analyze the time complexity of the following code snippet.
package main
func fibonacciDP(n int) int {
if n <= 1 {
return n
}
dp := make([]int, n+1)
dp[0], dp[1] = 0, 1
for i := 2; i <= n; i++ {
dp[i] = dp[i-1] + dp[i-2]
}
return dp[n]
}
This code calculates the nth Fibonacci number by storing previous results to avoid repeated work.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The for-loop that runs from 2 to n.
- How many times: Exactly n-1 times, once for each Fibonacci number from 2 up to n.
Each new Fibonacci number requires one addition operation, so the total work grows steadily with n.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 9 additions |
| 100 | 99 additions |
| 1000 | 999 additions |
Pattern observation: The number of operations grows linearly as n increases.
Time Complexity: O(n)
This means the time to compute the Fibonacci number grows in a straight line with the input size.
[X] Wrong: "Dynamic programming Fibonacci is still slow because it uses recursion like the naive method."
[OK] Correct: This code uses a loop and stores results, so it does not repeat calculations like naive recursion does.
Knowing how dynamic programming improves Fibonacci calculation shows you understand efficient problem solving, a key skill in interviews.
"What if we changed the dp array to only store the last two Fibonacci numbers instead of all? How would the time complexity change?"
Practice
Solution
Step 1: Understand recursion inefficiency
Simple recursion recalculates the same Fibonacci values multiple times, causing exponential time complexity.Step 2: Role of DP in optimization
DP stores previously computed Fibonacci numbers in a table (memoization or tabulation), avoiding repeated work and improving efficiency.Final Answer:
It avoids repeated calculations by storing intermediate results. -> Option AQuick Check:
DP stores results = avoids repeats [OK]
- Thinking DP uses less memory than recursion
- Believing DP calculates values randomly
- Confusing DP with plain recursion
Solution
Step 1: Understand slice initialization
To store Fibonacci numbers up to n, we need a slice of length n+1 to hold indices 0 through n.Step 2: Check each option
fib := make([]int, n+1) uses make with length n+1, correctly creating a slice. fib := []int{n} creates a slice with one element n, not size n+1. fib := new(int) creates a pointer to int, not a slice. fib := [n]int{} is invalid syntax for slice.Final Answer:
fib := make([]int, n+1) -> Option BQuick Check:
make slice with n+1 length = correct [OK]
- Using array syntax instead of slice
- Creating pointer instead of slice
- Initializing slice with wrong length
func fibDP(n int) int {
fib := make([]int, n+1)
fib[0], fib[1] = 0, 1
for i := 2; i <= n; i++ {
fib[i] = fib[i-1] + fib[i-2]
}
return fib[n]
}
fmt.Println(fibDP(5))Solution
Step 1: Trace Fibonacci values in slice
fib[0]=0, fib[1]=1; then fib[2]=1, fib[3]=2, fib[4]=3, fib[5]=5.Step 2: Return fib[5]
The function returns fib[5], which is 5.Final Answer:
5 -> Option DQuick Check:
Fibonacci(5) = 5 [OK]
- Confusing index with Fibonacci value
- Returning fib[n-1] instead of fib[n]
- Off-by-one errors in loop
func fibDP(n int) int {
fib := make([]int, n)
fib[0], fib[1] = 0, 1
for i := 2; i <= n; i++ {
fib[i] = fib[i-1] + fib[i-2]
}
return fib[n]
}Solution
Step 1: Check slice size and indexing
Slice fib is created with length n, but loop and return access fib[n], which is out of range.Step 2: Fix slice size
Increase slice size to n+1 so fib[n] is valid and no runtime error occurs.Final Answer:
Change slice size to n+1 to avoid index out of range. -> Option CQuick Check:
Slice size must cover all indices accessed [OK]
- Not increasing slice size causes runtime panic
- Changing initial values incorrectly
- Modifying loop incorrectly causing wrong results
Solution
Step 1: Understand constant space DP
We only keep last two Fibonacci numbers and update them iteratively to save space.Step 2: Analyze options
func fib(n int) int { a, b := 0, 1 for i := 2; i <= n; i++ { a, b = b, a+b } return b } correctly updates a and b simultaneously and returns b as fib(n). func fib(n int) int { fib := make([]int, n+1) fib[0], fib[1] = 0, 1 for i := 2; i <= n; i++ { fib[i] = fib[i-1] + fib[i-2] } return fib[n] } uses slice (not constant space). func fib(n int) int { if n <= 1 { return n } return fib(n-1) + fib(n-2) } is simple recursion (inefficient). func fib(n int) int { a, b := 0, 1 for i := 1; i < n; i++ { a = b b = a + b } return a } updates variables incorrectly causing wrong result.Final Answer:
func fib(n int) int { a, b := 0, 1 for i := 2; i <= n; i++ { a, b = b, a+b } return b } -> Option AQuick Check:
Update two vars simultaneously for constant space [OK]
- Using slice instead of variables for DP
- Incorrect variable update order causing wrong sums
- Using recursion without memoization
Ready to prove it?
Pass the test and this pattern moves unknown
