Problem overview
The Fibonacci sequence starts with 0 and 1, and every later number is the sum of the two before it: F(0) = 0, F(1) = 1, and F(n) = F(n - 1) + F(n - 2) for n greater than 1. The sequence runs 0, 1, 1, 2, 3, 5, 8, 13, and so on. The method fibonacci receives n, with 0 <= n <= 30, and must return F(n) using recursion.
For n = 4 the answer is 3: F(4) = F(3) + F(2) = 2 + 1. Time and space don't matter for this exercise.
Approach: the definition is the algorithm
The formula gives a recursive function almost word for word. It has two base cases, F(0) and F(1), and one recursive case that adds the results of two smaller calls.
The two base cases can be merged. F(0) = 0 and F(1) = 1, so for both of them the answer is n itself. A single check "if n is less than 2, return n" covers both.
Step by step
- Handle the base case first. If
n < 2, returnn. Without a base case, every call would start two more and the recursion would never stop. - Handle everything else by returning
fibonacci(n - 1) + fibonacci(n - 2).
The solution in Swift
class Solution {
func fibonacci(_ n: Int) -> Int {
if n < 2 {
return n
}
return fibonacci(n - 1) + fibonacci(n - 2)
}
}
The Swift details worth a closer look:
- No argument labels. The parameter is declared as
_ n: Int, so the recursive calls are writtenfibonacci(n - 1), notfibonacci(n: n - 1). - The method calls itself by name. Inside the class there is no need for
self.in front of the call. - Two calls in one expression. Swift evaluates
fibonacci(n - 1)first and thenfibonacci(n - 2), and adds the two results. - Overflow.
Intis 64 bits, and F(30) = 832040 is tiny compared to its range. For much largernthe sum would eventually overflow, which stops the program in Swift instead of wrapping.
Complexity
Time: exponential. Every call with n of 2 or more makes two more calls, and they recompute the same values again and again. fibonacci(4) evaluates fibonacci(2) twice, and for larger n the repetition snowballs. Computing F(10) takes 177 calls, and F(30) takes 2,692,537. The count grows by about 1.6 times for each step in n, roughly O(1.618^n). That is acceptable for the limit of 30, but not much beyond it.
Space: O(n). The calls form a chain at most n frames deep on the call stack. The two branches at each level are evaluated one after the other, not together.
The repeated work can be removed by remembering results already computed, or by building the sequence from the bottom up with a loop. This lesson practises the plain recursion.
Edge cases and common mistakes
n = 0andn = 1. Both returnn, giving 0 and 1.- Checking only
n == 0. Thenfibonacci(1)would callfibonacci(0)andfibonacci(-1), and the recursion would never end for any input. - Returning 1 for the base case. That gives F(0) = 1, which shifts the whole sequence.
- Calling with the same
n. A call likefibonacci(n)inside the function never gets smaller. - Forgetting the second call.
fibonacci(n - 1) + fibonacci(n - 1)gives powers of two, not Fibonacci numbers.
Testing
n = 0gives0.n = 1gives1.n = 2gives1.n = 4gives3.n = 10gives55.n = 30gives832040.
