What space complexity measures
Space complexity measures how much memory an algorithm needs as a function of its input size. It is the companion of time complexity and uses the same Big O notation, with the same rules: describe the growth, ignore constant factors, and keep the dominant term. A function that needs memory for ten values or for twenty values, no matter how large the input is, still has the same space complexity.
In TypeScript the things that take up memory are the variables you declare and the arrays, strings, objects, Maps and Sets you build. Type annotations take no memory at run time: they are erased when the code is compiled to JavaScript. Only the values matter.
Constant space: O(1)
function sum(a: number, b: number): number {
const total: number = a + b;
return total;
}
The function holds three numbers: the inputs a and b, and the helper total. Calling it with bigger numbers doesn't change that count, so the space is fixed. This is constant space, written O(1). The word "constant" doesn't mean "one variable"; it means the memory doesn't grow with the input.
Linear space: O(n)
function generate(n: number): number[] {
const numbers: number[] = [];
for (let i = 0; i < n; i++) {
numbers.push(i);
}
return numbers;
}
Here the array numbers ends up with n elements, so the memory grows in step with n. Twice the n, twice the memory. That is linear space, O(n). The loop variable i is one more number, but a constant on top of n is dropped.
Quadratic space: O(n²)
function generate(n: number): number[][] {
const numbers: number[][] = [];
for (let i = 0; i < n; i++) {
numbers.push([]);
for (let j = 0; j < n; j++) {
numbers[i].push(j);
}
}
return numbers;
}
This builds n rows, each holding n numbers, so n * n values in total. The memory is proportional to the square of n: quadratic space, O(n²). Any grid or table with n rows and n columns costs this much.
Input space and auxiliary space
When people say "space complexity" they sometimes mean different things, so it helps to separate two parts:
- Input space is the memory taken by the arguments you receive.
- Auxiliary space (also called extra space) is the additional memory the algorithm uses while it runs, not counting the input.
Space complexity as defined here is their sum. Problems that say "use O(1) extra space" are talking about auxiliary space only.
function sum(arr: number[]): number {
let total = 0;
for (const num of arr) {
total += num;
}
return total;
}
The input array has n elements, so the input space is O(n). The function declares only total and num, two numbers regardless of n, so its auxiliary space is O(1). When a problem asks for O(1) extra space, this is the kind of function it wants.
Copying versus changing in place
The difference between auxiliary space O(n) and O(1) is often a question of whether you build a new array or reuse the old one. Reversing an array shows both:
function reverseCopy(arr: number[]): number[] {
const out: number[] = [];
for (let i = arr.length - 1; i >= 0; i--) {
out.push(arr[i]);
}
return out;
}
function reverseInPlace(arr: number[]): void {
let l = 0, r = arr.length - 1;
while (l < r) {
const t = arr[l];
arr[l] = arr[r];
arr[r] = t;
l++;
r--;
}
}
reverseCopy allocates a second array of n elements, so it uses O(n) extra space and leaves the input as it was. reverseInPlace swaps elements inside the input with a few index variables, so it uses O(1) extra space, but it changes the caller's array. Which one is better depends on whether the caller still needs the original.
Hidden memory
Some memory use isn't visible as a declaration:
- Recursion. Each active call occupies a stack frame. A function like
countDown(n)that callscountDown(n - 1)untilnis 0 hasnframes alive at the deepest point, so it usesO(n)space even though it declares no array. Very deep recursion can end with aRangeError(stack overflow): with a depth of a million,countDownthrows one in Node. - Copies.
slice,concat, the spread syntax[...arr]and string concatenation all create new values, and the new value's size counts. - Collections. A
SetorMapthat stores up tonentries costsO(n).
Time against space
The two often trade against each other. Remembering the values you have already seen in a Set can turn a quadratic search into a linear one, at the cost of O(n) extra space. When you solve a problem, state both costs: "O(n) time and O(1) extra space".
Common mistakes
- Counting the input as extra space when the problem asks for auxiliary space, or leaving it out when it asks for total space.
- Saying a function that returns a new array of size
nusesO(1)space because it has few variables. The returned array is memory the function created. - Forgetting the call stack in recursive solutions.
- Believing type annotations use memory. They exist only at compile time.
Key takeaways
- Space complexity uses Big O to describe how memory grows with the input.
- A fixed number of variables is
O(1); an array ofnvalues isO(n); annbyngrid isO(n²). - Space complexity equals input space plus auxiliary space; "extra space" means only the auxiliary part.
- Recursion depth, copies and collections all count.