Every space question you will ever meet falls into one of these cells. The Cell column is the label we tag each worked example with.
Cell
Case class
What makes it distinct
Typical auxiliary answer
A
Constant scratch, big input
fixed # of scalars, in-place
O(1) aux, O(n) total
B
Linear scratch you build
a new array of size ∝n
O(n) aux
C
Recursion — linear depth
stack grows to depth n
O(n) aux
D
Recursion — logarithmic depth
balanced divide-and-conquer
O(logn) aux
E
Zero / degenerate input
n=0 or n=1, empty structures
still valid — check the limit
F
2D table
grid of size n×m
O(n⋅m) or O(n2)
G
Exponential output
must store 2n things
O(2n⋅n)
H
The exam twist
time = space; branching recursion
depth, not node count
I
Real-world word problem
translate English → cells
depends — you decide
We now walk all nine cells with fully worked examples.
The figure above is the mental model for the whole page: a table holds two piles of cells — the fixed input pile (blue, you can't shrink it) and the auxiliary pile (yellow, the part your cleverness controls). Recursion adds a stack of trays (red) that all sit on the table at once.
Look at the red tower in the figure. Each call to rec_sum is paused waiting for the deeper call to finish, so its stack frame stays alive.
Why this step? A frame can only be freed after the call it is waiting on returns — see Recursion and the call stack.
Count peak simultaneous frames. The deepest call is at i=n; below it sit frames i=n−1,…,0. That is n+1 frames all alive at once.
Why this step? Space is peak simultaneous cells, and here the peak is the moment just before the first return.
Multiply by frame size. Each frame holds O(1) data, so total =(n+1)×O(1)=O(n).
Why this step? Auxiliary space of recursion = depth × frame size.
Verify: The iterative twin — a for loop with one accumulator — never stacks frames, so its auxiliary is O(1). Same answer, same time, but O(n) vs O(1) space. The recursion cost was real. ✅
Track the halving in the figure. Each call throws away half the remaining range.
Why this step? If you halve n repeatedly, the count of halvings to reach size 1 is log2n.
Read off the depth. Number of nested calls =log2n, so at most log2n frames coexist.
Why this step? Depth = number of times we can halve n before hitting the base case.
Apply the recursion rule. Auxiliary =log2n×O(1)=O(logn).
Why this step? Same "depth × frame size" law as Cell C, but the depth is now logarithmic.
Verify: For n=1024=210, depth =log21024=10. Ten frames, not a thousand. This is exactly why balanced Quick Sort uses O(logn) average auxiliary — its partition is in-place and its recursion depth is ≈log2n when the pivots split evenly. ✅
Look at the recursion tree in the figure. Yes, there are ≈2nnodes total — but they are not all alive at once.
Why this step? Time counts every node ever visited; space counts only nodes alive simultaneously.
Trace one path down the tree. The computer explores depth-first: fib(n) → fib(n-1) → fib(n-2) → .... Only the frames along one root-to-leaf path are on the stack at any instant.
Why this step? When a branch returns, its frame is freed before the sibling branch starts.
Measure the longest path. The deepest chain is fib(n)→fib(n−1)→⋯→fib(1), length n. So peak stack depth =O(n).
Why this step? Depth of the tree, not size of the tree, sets the space.
Verify: time =O(2n) (number of nodes), space =O(n) (tree height). They genuinely differ. If a problem says "give the space complexity of naive fib," the answer is O(n), notO(2n). ✅
A function builds an n×n matrix ::: Cell F → O(n2) auxiliary.
A function recurses by halving a sorted array ::: Cell D → O(logn).
A branching recursion visiting 3n nodes but only n deep ::: Cell H → O(n) space (height), not O(3n).
Reversing a string in place with two pointers ::: Cell A → O(1).
Generating every permutation and storing them all ::: Cell G-flavour → O(n!⋅n) (count × length).
An algorithm called on an empty array ::: Cell E → still O(1) constant, not zero.