Problem overview
The function fibonacci receives an integer n and returns F(n), the n-th Fibonacci number. The sequence starts F(0) = 0 and F(1) = 1, and every later number is the sum of the two before it: F(n) = F(n - 1) + F(n - 2).
The sequence begins 0, 1, 1, 2, 3, 5, 8, 13. So F(2) = 1 + 0 = 1, F(3) = 1 + 1 = 2 and F(4) = 2 + 1 = 3. The task asks for O(n) time and O(1) extra space.
Approach: keep only the last two numbers
The definition looks like a recursive function, but a direct recursion calls itself twice per level and recomputes the same values again and again. Its running time grows exponentially.
The loop version works because each new number needs only the previous two. Instead of storing the whole sequence, keep two variables, prev and curr, holding F(i - 2) and F(i - 1). On each pass, compute F(i) from them, then slide the window one step: the old curr becomes prev and the new number becomes curr. That is n - 1 passes (for F(2) up to F(n)) and two variables of memory.
Take n = 4. Start with prev = 0, curr = 1. At i = 2, the new value is 1, and the pair becomes (1, 1). At i = 3 it is 2, and the pair becomes (1, 2). At i = 4 it is 3, and the pair becomes (2, 3). The answer is curr, which is 3.
Step by step
- Handle the base cases. If
nis less than 2, returnn. That covers bothF(0) = 0andF(1) = 1with a single check. - Set the starting pair. Declare
prevandcurrtogether with:=, as 0 and 1, the values ofF(0)andF(1). - Loop from 2 to
n. Declareiin theforheader, starting at 2 and running while it is at mostn, so every number fromF(2)throughF(n)is computed. - Compute the new number. Declare
nextascurr + prev. - Slide the window. Assign
currtoprevfirst, thennexttocurr. This order matters: ifcurrwere overwritten first, its old value would be lost beforeprevcould take it. - Return
curr. After the last pass it holdsF(n).
The solution in Go
func fibonacci(n int) int {
if n < 2 {
return n
}
prev, curr := 0, 1
for i := 2; i <= n; i++ {
next := curr + prev
prev = curr
curr = next
}
return curr
}
Go details to notice:
- Multiple assignment.
prev, curr := 0, 1declares two variables in one statement. Go also lets you update a pair at once withprev, curr = curr, prev + curr, because the right side is fully evaluated before any assignment. That would replace the three lines in the loop. The lesson uses a namednextto show each step. - Early return. The
ifwith areturnhandles the special cases up front, so the rest of the function can assumen >= 2. Go style prefers this to anelseblock. nextis not a keyword. Go has nonextkeyword, so the name is fine. A variable namednextis local to the loop body.- Unused variables don't compile. Declaring
nextand not using it would be a compile error. Here it is used twice. - Overflow. An
intis 64 bits, and overflow wraps silently.fibonacci(92)is 7540113804746346429, which fits.fibonacci(93)returns a negative number,-6246583658587674878, because the true value is larger than the biggestint.
Complexity
Time: O(n). The loop runs n - 1 times with constant work per pass.
Space: O(1). The variables prev, curr, next and i use the same memory whatever the size of n. Keeping all the numbers in a slice would work too, but it would cost O(n) space.
Edge cases and common mistakes
n = 0andn = 1. Without the early return, the loop would not run, and the function would returncurr, which is 1. That is right forn = 1and wrong forn = 0, which should give 0.n = 2. The loop runs once and gives 1.- Wrong order of updates. Setting
curr = nextbeforeprev = currmakes both variables equal the new number, so the sequence stops growing correctly. - Looping to
n - 1. An off-by-one error here returnsF(n - 1). The comparison must bei <= n. - Naive recursion. The two-call recursive version is correct but takes exponential time, so it becomes unusable for
naround 50.
Testing
n = 0gives0.n = 1gives1.n = 4gives3.n = 10gives55.n = 50gives12586269025.