Tabulation Bottom Up DP in DSA C++ - Time & Space Complexity
We want to understand how the time needed grows when using tabulation in bottom-up dynamic programming.
Specifically, how the number of steps changes as input size increases.
Analyze the time complexity of the following code snippet.
int fib(int n) {
int dp[n+1];
dp[0] = 0;
dp[1] = 1;
for (int 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: Exactly n-1 times, once for each i from 2 to n.
Each new input number adds one more step to fill the dp array.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 9 steps |
| 100 | About 99 steps |
| 1000 | About 999 steps |
Pattern observation: The number of steps grows roughly in a straight line with input size.
Time Complexity: O(n)
This means the time needed grows directly in proportion to the input size.
[X] Wrong: "Tabulation takes more time than recursion because it uses loops."
[OK] Correct: Although tabulation uses loops, it avoids repeated calculations, so it actually runs faster than naive recursion.
Understanding how tabulation scales helps you explain efficient solutions clearly and confidently in interviews.
"What if we changed the dp array to store results for only the last two Fibonacci numbers instead of all? How would the time complexity change?"
Practice
Tabulation Bottom Up DP in dynamic programming?Solution
Step 1: Understand bottom-up approach
Tabulation means filling a table starting from the smallest subproblems, so we solve all smaller parts first.Step 2: Compare with other methods
Unlike recursion without memory, bottom-up avoids repeated work by storing results in a table.Final Answer:
Build a table from the smallest subproblems up to the main problem -> Option AQuick Check:
Bottom-up DP = Build table from small to big [OK]
- Confusing bottom-up with recursion without memoization
- Thinking it starts from the largest problem
- Ignoring the use of a table to store results
Solution
Step 1: Check array initialization
int dp[100] = {0}; dp[1] = 1; initializes dp with zeros and sets dp[1] = 1, which is correct for Fibonacci base cases.Step 2: Identify errors in other options
int dp[]; dp[1] = 1; has no size for dp array, invalid in C++. int dp[100]; dp[0] = 1; sets dp[0] = 1 which is incorrect base case. int dp[100] = {1}; dp[2] = 1; initializes dp with 1 at dp[0], which is wrong.Final Answer:
int dp[100] = {0}; dp[1] = 1; -> Option BQuick Check:
Correct base initialization = int dp[100] = {0}; dp[1] = 1; [OK]
- Not specifying array size
- Wrong base case initialization
- Assuming default values without initialization
int fib(int n) {
int dp[6] = {0};
dp[1] = 1;
for (int i = 2; i <= n; i++) {
dp[i] = dp[i-1] + dp[i-2];
}
return dp[n];
}
int main() {
std::cout << fib(5);
return 0;
}Solution
Step 1: Trace dp array filling
dp[0]=0, dp[1]=1; then dp[2]=1, dp[3]=2, dp[4]=3, dp[5]=5 by adding previous two.Step 2: Return dp[5]
dp[5] is 5, so output is 5.Final Answer:
5 -> Option AQuick Check:
Fibonacci(5) = 5 [OK]
- Off-by-one errors in indexing
- Confusing dp[0] and dp[1] values
- Returning wrong dp index
int factorial(int n) {
int dp[100];
dp[0] = 1;
for (int i = 1; i <= n; i++) {
dp[i] = dp[i-1] * i;
}
return dp[n];
}Solution
Step 1: Check dp array size
dp array size is fixed at 100, so if n > 99, dp[i] access is out of bounds causing error.Step 2: Analyze other parts
Initialization and loop logic are correct; loop starts at 1 and dp[0] = 1 is base case.Final Answer:
dp array size might be too small for large n -> Option CQuick Check:
Array size must fit n [OK]
- Assuming dp size is always enough
- Starting loop at wrong index
- Ignoring base case initialization
dp[11] will hold after running this code?int coins[] = {1, 3, 5};
int n = 11;
int dp[12];
dp[0] = 0;
for (int i = 1; i <= n; i++) {
dp[i] = 1000; // large number
for (int c : coins) {
if (i - c >= 0) {
dp[i] = std::min(dp[i], dp[i-c] + 1);
}
}
}
std::cout << dp[n];Solution
Step 1: Understand DP logic for coin change
dp[i] stores minimum coins for amount i. For 11, check coins 1,3,5 and pick minimum.Step 2: Calculate dp values up to 11
dp[0]=0; dp[1]=1; dp[2]=2; dp[3]=1; dp[4]=2; dp[5]=1; dp[6]=2; dp[7]=3; dp[8]=2; dp[9]=3; dp[10]=2; dp[11]=3 (e.g., 5+5+1 or 3+3+5)Final Answer:
3 -> Option DQuick Check:
Minimum coins for 11 = 3 [OK]
- Not initializing dp[0] = 0
- Using max int instead of large number
- Forgetting to check i - coin >= 0
Ready to prove it?
Pass the test and this pattern moves unknown
