LeetCode #509 Easy

Fibonacci Number

Fibonacci Number: compute F(n), where F(0) = 0, F(1) = 1, and every later term is the sum of the two before it.

Constraints
  • 0 <= n <= 30
  • F(0) = 0, F(1) = 1
  • F(n) = F(n - 1) + F(n - 2) for n > 1
mathdynamic programmingrecursionmemoization
Open on LeetCode ↗
Fibonacci Number diagramA labelled diagram of the structure this problem turns on.each term needs only the two before it011235F(0)F(1)F(2)F(3)F(4)F(5)1 + 2 = 3so a full table is waste — two variables sufficenaive recursion recomputes these overlaps ≈ φⁿ times
02

Intuition

The recurrence names exactly two dependencies, so a full table is unnecessary — only the previous two values matter at any moment. Carrying that pair forward and updating it n times computes the answer in linear time with two variables. The plain recursive definition, by contrast, recomputes the same subproblems exponentially often, which is what makes this the standard illustration of why overlapping subproblems need memoising or flattening.

How to spot this pattern

A recurrence that depends on a fixed number of previous terms can always be rolled into that many variables instead of a full table. The signal is a fixed, small look-back. Climbing Stairs, Min Cost Climbing Stairs, and House Robber are the same optimisation.

03

Approach

Try it first

Before reading on: count how many times fib(2) is evaluated by the naive recursion for fib(6). Then work out how many previous values you actually need to keep, and write the update without a temporary variable.

1

Why naive recursion is exponential

Writing fib(n) = fib(n-1) + fib(n-2) directly produces a call tree whose node count grows like the Fibonacci numbers themselves, roughly φⁿ where φ ≈ 1.618. The cause is overlap: fib(n-2) is evaluated once inside fib(n-1) and again as the second branch, and that duplication compounds at every level. fib(40) makes over 300 million calls to compute a value that fits in an int. The problem is not recursion but the absence of memory between branches.

2

Flattening the recurrence into two variables

Because F(i) depends only on F(i-1) and F(i-2), the whole table can be collapsed to a rolling pair. Hold prev = F(0) = 0 and curr = F(1) = 1, then repeat prev, curr = curr, prev + curr for n - 1 steps; after the loop curr holds F(n). Python's simultaneous assignment evaluates the entire right-hand side before rebinding, so both updates use the old values. In C++ and Java a temporary is required, and overwriting prev first is the classic way to corrupt the sequence.

3

Base cases and cost

F(0) = 0 and F(1) = 1 must be handled before the loop, since the iteration starts from an already-formed pair. Returning n covers both at once, because F(0) is 0 and F(1) is 1. The loop then runs O(n) times with O(1) space, holding two numbers rather than a table of n + 1. A memoised recursion reaches the same O(n) time but pays O(n) space for the cache plus the call stack, so the iterative form is strictly better here — the memoised version is worth knowing as the general technique, not as the answer to this problem.

04

Solution & live demo

1class Solution:
2 def fib(self, n):
3 if n < 2:
4 return n
5 prev, curr = 0, 1
6 for _ in range(2, n + 1):
7 prev, curr = curr, prev + curr
8 return curr
05

Common pitfalls

Naive recursion without memoisation

✗ Wrong
def fib(self, n):
    if n < 2:
        return n
    return self.fib(n - 1) + self.fib(n - 2)
✓ Right
prev, curr = 0, 1
for _ in range(2, n + 1):
    prev, curr = curr, prev + curr

The same subproblems are recomputed across branches, giving roughly φⁿ calls. It is correct but times out well before large n, because nothing carries results between the two recursive branches.

Updating the pair in sequence rather than simultaneously

✗ Wrong
prev = curr;
curr = prev + curr;
✓ Right
int next = prev + curr;
prev = curr;
curr = next;

After the first assignment prev already holds the old curr, so the sum adds curr to itself and produces powers of two instead of Fibonacci numbers. Python's tuple assignment avoids this by evaluating the right side first.

Off-by-one in the loop range

✗ Wrong
for _ in range(2, n):
✓ Right
for _ in range(2, n + 1):

The pair starts at F(0) and F(1), so reaching F(n) needs iterations for indices 2 through n inclusive. Stopping at n - 1 returns F(n - 1).

06

Edge cases

n = 0

Returned directly as 0 before the loop begins.

n = 1

Returned directly as 1; the rolling pair is already correct.

n = 2

One iteration produces 1, the sum of the two base cases.

n = 30, the constraint maximum

F(30) = 832040, comfortably inside a 32-bit int.

Swapping the updates in the wrong order

Overwriting prev first feeds a corrupted value into the sum and derails every later term.

07

Complexity

Time
O(n)
Space
O(1)
Two variables replace the full table. A memoised recursion matches the time but pays O(n) for the cache and stack.