Tabulation Bottom Up DP in DSA Go - Time & Space Complexity
We want to understand how the time needed grows when using tabulation in bottom-up dynamic programming.
Specifically, how does the number of steps change as the input size increases?
Analyze the time complexity of the following code snippet.
func fib(n int) int {
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 using bottom-up tabulation.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The for-loop that fills the dp array from 2 to n.
- How many times: It runs (n - 1) times, once for each number from 2 up to n.
As n grows, the loop runs more times, increasing the steps linearly.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 9 additions |
| 100 | About 99 additions |
| 1000 | About 999 additions |
Pattern observation: The number of operations grows roughly in a straight line with n.
Time Complexity: O(n)
This means the time needed grows directly in proportion to the input size.
[X] Wrong: "Tabulation always takes more time than recursion because it uses loops."
[OK] Correct: Tabulation avoids repeated work by storing results, so it actually runs faster than naive recursion which repeats calculations many times.
Understanding how tabulation scales helps you explain efficient solutions clearly and confidently in interviews.
"What if we changed the dp array to only store the last two results instead of all n? How would the time complexity change?"
Practice
Tabulation Bottom Up DP in dynamic programming?Solution
Step 1: Understand tabulation approach
Tabulation means filling a table starting from the smallest subproblems.Step 2: Compare with other methods
Unlike recursion, tabulation solves subproblems first and uses their answers to solve bigger problems.Final Answer:
Build a table from the smallest subproblems up to the main problem -> Option CQuick Check:
Tabulation = Bottom Up DP [OK]
- Confusing tabulation with recursion
- Thinking tabulation starts from the largest problem
- Ignoring the use of a table to store results
Solution
Step 1: Understand Go slice initialization
To create a slice of integers with length n+1 filled with zeros, use make([]int, n+1).Step 2: Check other options
dp := make([]int, n) creates size n, not n+1; dp := []int{n+1} is invalid syntax; dp := new(int, n+1) is invalid for slices.Final Answer:
dp := make([]int, n+1) -> Option DQuick Check:
make([]int, n+1) creates zero-filled slice [OK]
- Using wrong slice size (n instead of n+1)
- Using new() which returns pointer, not slice
- Incorrect slice literal syntax
func fib(n int) int {
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]
}
fmt.Println(fib(5))Solution
Step 1: Trace DP table filling for n=5
dp[0]=0, dp[1]=1; then dp[2]=1, dp[3]=2, dp[4]=3, dp[5]=5.Step 2: Return dp[5]
The function returns dp[5], which is 5.Final Answer:
5 -> Option AQuick Check:
Fibonacci(5) = 5 [OK]
- Off-by-one errors in loop
- Wrong base cases initialization
- Confusing dp indices
func factorial(n int) int {
dp := make([]int, n+1)
dp[0] = 1
for i := 1; i < n; i++ {
dp[i] = i * dp[i-1]
}
return dp[n]
}Solution
Step 1: Check loop range for factorial calculation
Factorial needs to compute dp[n], so loop must include i = n (i <= n).Step 2: Identify impact of loop range
Current loop stops at i = n-1, so dp[n] remains zero, causing wrong return.Final Answer:
Loop should run until i <= n, not i < n -> Option BQuick Check:
Loop must cover all factorial steps [OK]
- Stopping loop before n
- Wrong base case initialization
- Returning wrong dp index
coins := []int{1, 2, 5} and an amount amount := 5, which bottom-up DP code snippet correctly computes the minimum number of coins needed to make the amount? Assume impossible cases return -1.Solution
Step 1: Initialize dp with large values and base case
Set dp size to amount+1, fill with amount+1 (impossible large), and dp[0]=0.Step 2: Update dp with minimum coins for each amount
For each amount i, check all coins c; if c <= i, update dp[i] = min(dp[i], dp[i-c]+1).Step 3: Return result or -1 if impossible
If dp[amount] > amount, return -1; else return dp[amount].Final Answer:
Option A code snippet -> Option AQuick Check:
Proper initialization and min update needed [OK]
- Wrong dp size or initialization
- Not checking if dp[i-c] is valid
- Incorrect base case dp[0]
Ready to prove it?
Pass the test and this pattern moves unknown
