Why it shows up everywhere in practice: It’s the classic teaching vehicle for a few foundational concepts, which is why it appears so often in coursework and interviews.

A deceptively simple sequence that’s really a lesson in how you compute, not what you compute.

1. Iterative

#include <iostream>
#include <cstdint>

// Prints the first n Fibonacci numbers
void fibSeries(int n) {
    uint64_t a = 0, b = 1;
    for (int i = 0; i < n; ++i) {
        std::cout << a << " ";
        uint64_t next = a + b;
        a = b;
        b = next;
    }
    std::cout << "\n";
}

int main() {
    fibSeries(10);   // 0 1 1 2 3 5 8 13 21 34
    return 0;
}

O(n) time, O(1) space. This is what you'd want in an interview unless asked otherwise.

O(n) time, O(1) space. This is what you’d want in an interview unless asked otherwise.

2. Recursive

uint64_t fib(int n) {
    if (n < 2) return n;        // base cases: fib(0)=0, fib(1)=1
    return fib(n - 1) + fib(n - 2);
}

Clean to read, but O(2ⁿ) time because it recomputes the same subproblems over and over. Good for explaining recursion; bad for anything past n ≈ 40.

3. Memoized recursion

#include <vector>

uint64_t fib(int n, std::vector<uint64_t>& memo) {
    if (n < 2) return n;
    if (memo[n] != 0) return memo[n];  // already computed
    return memo[n] = fib(n - 1, memo) + fib(n - 2, memo);
}

Brings the recursive version down to O(n) time, O(n) space. This is the bridge between naive recursion and the iterative dynamic programming version — worth being able to write from memory since it’s the pattern for most dynamic programming problems.