Fibonacci Using Recursion in DSA Rust - Time & Space Complexity
We want to understand how the time needed to find a Fibonacci number grows as the input number gets bigger.
How does the number of steps change when we use recursion to find Fibonacci numbers?
Analyze the time complexity of the following code snippet.
fn fibonacci(n: u32) -> u32 {
if n == 0 || n == 1 {
return n;
}
fibonacci(n - 1) + fibonacci(n - 2)
}
This code calculates the nth Fibonacci number by calling itself twice for smaller numbers until it reaches 0 or 1.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Recursive calls to fibonacci for n-1 and n-2.
- How many times: Each call splits into two more calls until base cases (0 or 1) are reached.
Each number requires calculating two smaller Fibonacci numbers, causing the number of calls to grow very fast.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 177 calls |
| 20 | About 21,891 calls |
| 30 | About 2,692,537 calls |
Pattern observation: The number of calls roughly doubles with each increase in n, growing exponentially.
Time Complexity: O(2^n)
This means the time needed grows very fast, doubling with each step up in n, making it slow for large numbers.
[X] Wrong: "The recursive Fibonacci runs in linear time because it just counts down from n to 0."
[OK] Correct: Each call makes two more calls, so the total calls grow much faster than just counting down.
Understanding this helps you explain why simple recursion can be slow and why techniques like memoization improve performance.
"What if we add a memory to store results (memoization)? How would the time complexity change?"
Practice
Solution
Step 1: Understand Fibonacci sequence definition
The Fibonacci sequence is defined such that each number is the sum of the two numbers before it.Step 2: Relate to recursion
Recursion calls the function for the two previous numbers and adds their results.Final Answer:
Each number is the sum of the two preceding numbers -> Option DQuick Check:
Fibonacci = sum of two previous numbers [OK]
- Thinking Fibonacci multiplies previous numbers
- Confusing subtraction or division with addition
- Assuming Fibonacci squares previous number
Solution
Step 1: Check Rust function signature syntax
Rust requires parameter types and return type specified, e.g., fn name(param: type) -> return_type.Step 2: Match correct signature for Fibonacci
Fibonacci takes an integer and returns an integer, so fn fibonacci(n: i32) -> i32 is correct.Final Answer:
fn fibonacci(n: i32) -> i32 -> Option AQuick Check:
Rust needs types and return type [OK]
- Omitting parameter type
- Missing return type
- Using void instead of () or proper return type
fn fibonacci(n: i32) -> i32 {
if n <= 1 {
n
} else {
fibonacci(n - 1) + fibonacci(n - 2)
}
}
fn main() {
println!("{}", fibonacci(5));
}Solution
Step 1: Trace fibonacci(5) calls
fibonacci(5) = fibonacci(4) + fibonacci(3). Breaking down recursively, fibonacci(5) = 5.Step 2: Confirm base cases and sums
Base cases: fibonacci(0)=0, fibonacci(1)=1. Summing up gives fibonacci(5) = 5.Final Answer:
5 -> Option BQuick Check:
Fibonacci(5) = 5 [OK]
- Confusing fibonacci(5) with fibonacci(6)
- Miscounting base cases
- Adding wrong recursive results
fn fibonacci(n: i32) -> i32 {
if n == 0 {
0
} else if n == 1 {
1
} else {
fibonacci(n - 1) - fibonacci(n - 2)
}
}Solution
Step 1: Check base cases
Base cases for n=0 and n=1 return 0 and 1 correctly.Step 2: Analyze recursive step
The recursive step uses subtraction (fibonacci(n - 1) - fibonacci(n - 2)) instead of addition, which is incorrect for Fibonacci.Final Answer:
The recursive step uses subtraction instead of addition -> Option CQuick Check:
Fibonacci sums previous two, not subtracts [OK]
- Using subtraction in recursive step
- Forgetting to return values
- Incorrect base case values
Solution
Step 1: Understand recursion inefficiency
Recursive Fibonacci recalculates the same values many times, causing slow performance.Step 2: Apply memoization
Memoization stores results of previous calls in a cache to reuse, avoiding repeated work.Final Answer:
Use memoization to store and reuse computed results -> Option AQuick Check:
Memoization optimizes recursion by caching [OK]
- Increasing recursion depth doesn't fix repeated work
- Using loops changes approach, not recursion optimization
- Calling with negative numbers causes errors
Ready to prove it?
Pass the test and this pattern moves unknown
