DSA Notes
A complete guide to space complexity analysis — what counts as auxiliary space, how to analyze iterative and recursive algorithms, how recursion creates implicit stack space, common space complexity classes with examples, and the fundamental time-space tradeoffs every programmer must understand.
Introduction
Every algorithm uses two types of resources: time and space (memory). While time complexity tells you how many operations an algorithm performs, space complexity tells you how much additional memory it requires.
In the era of multi-gigabyte RAM and terabyte storage, you might wonder why space complexity still matters. The answer is that it matters more than ever:
- Mobile applications run on devices with 2-6 GB RAM shared across dozens of processes
- Embedded systems (microcontrollers, IoT devices) may have only a few kilobytes of RAM
- Server applications processing millions of requests simultaneously need each request to use minimal memory
- In-memory databases and caches have strict memory budgets
- Large dataset processing — sorting 100 million records in-memory requires careful space management
- Recursive algorithms have hidden space costs (the call stack) that can cause stack overflow
Understanding space complexity helps you make informed decisions about the memory-speed tradeoff in every algorithm you write.
O(1) — Constant Space (In-Place Algorithms)
An algorithm uses O(1) space if it uses only a fixed number of additional variables, regardless of the input size.
These are called in-place algorithms — they work directly on the input without significant additional memory.
Examples
O(1) space is the gold standard for sorting algorithms. Bubble Sort, Selection Sort, Insertion Sort, and Heap Sort all achieve O(1) auxiliary space.
O(log n) — Logarithmic Space
Algorithms with O(log n) space usually achieve this through recursive calls that halve the input — the recursion depth is proportional to log n.
Example — Binary Search (Recursive)
Space analysis:
Each recursive call creates one stack frame (containing the parameters left, right, mid, and the return address). The maximum recursion depth is log₂(n) — after log n halvings, the search range is empty.
| Frame 1 | binary_search(array, target, 0, 7) ← deepest call |
| Frame 2 | binary_search(array, target, 0, 3) |
| Frame 3 | binary_search(array, target, 0, 1) |
| Frame 4 | binary_search(array, target, 0, 0) |
| Maximum depth | 4 = log₂(8) |
| Stack frames | 4 = O(log n) |
| Space | O(log n) |
Contrast with iterative version:
The iterative version achieves O(1) space by managing the search range explicitly in variables rather than implicitly through the call stack.
Example — Quick Sort
def quicksort(array, low, high):
if low < high:
pivot_index = partition(array, low, high)
quicksort(array, low, pivot_index - 1) # Recursive call
quicksort(array, pivot_index + 1, high) # Recursive callSpace analysis:
Quick Sort's recursion depth depends on pivot quality:
- Best case (balanced pivots): Each call halves the input → depth = log n → O(log n) space
- Worst case (unbalanced pivots): Each call reduces size by 1 → depth = n → O(n) space
O(n) — Linear Space
An algorithm uses O(n) space if it creates an additional structure proportional in size to the input.
Example — Merge Sort
Space analysis:
At any point during execution, the active call stack has log n levels. The merge step at each level creates a temporary array. The maximum space in use at any moment is:
- The recursion stack: O(log n) stack frames
- The merge buffer at the current level: O(n) for the top-level merge
- Total auxiliary space: O(n)
This O(n) auxiliary space is Merge Sort's main disadvantage compared to Heap Sort (which sorts in O(1) space with the same O(n log n) time complexity).
Example — Counting Duplicates with Hash Map
Example — Reversing by Creating a Copy
def reverse_copy(array):
"""
Return a reversed copy — does not modify the original.
Creates a new array of the same size — O(n) space.
"""
result = []
for element in reversed(array):
result.append(element) # New array grows to n elements
return result
# Space: O(n)O(n²) — Quadratic Space
Quadratic space usually appears when creating a 2D table for dynamic programming.
Example — Longest Common Subsequence DP Table
Space optimization for LCS:
Notice that each row of the DP table only depends on the previous row. We can reduce from O(n²) to O(n):
Recursion and Implicit Stack Space
Recursive algorithms have implicit space cost from the call stack. Every function call adds a stack frame containing:
- Function parameters
- Local variables
- Return address (where to go when the function returns)
This stack space accumulates with each nested call.
Stack Frame Size
In most languages, a stack frame for a simple function is 20-100 bytes. For n = 100,000 recursive calls, this is 2-10 MB — manageable. For n = 1,000,000, it may be 100-1000 MB — potentially causing a stack overflow crash.
Example — Factorial Recursion
def factorial(n):
if n <= 1: return 1
return n * factorial(n - 1) # One new stack frame per callFor n = 10,000, Python's default recursion limit would be exceeded (Python limits recursion to ~1000 by default).
Iterative version — O(1) space:
def factorial_iterative(n):
result = 1
for i in range(2, n + 1):
result *= i
return result
# Space: O(1) — no recursion, just one variableExample — Tree Traversal Space
The space used by tree traversal depends on the tree's height (maximum recursion depth):
def inorder_traversal(root):
"""
In-order traversal of a binary tree.
Recursion depth = height of the tree.
"""
if root is None:
return
inorder_traversal(root.left)
print(root.value)
inorder_traversal(root.right)Balanced tree of n nodes
Height = log₂(n)
Space: O(log n)
Completely skewed tree (like a linked list)
Height = n
Space: O(n)
This is why balanced trees (AVL trees, Red-Black trees) are important — they guarantee O(log n) height and thus O(log n) space for tree operations.
Time-Space Tradeoffs — The Core Decision
The most important practical application of space complexity analysis is making informed time-space tradeoffs. Almost always, you can trade more memory for faster execution, or use less memory at the cost of more computation.
Tradeoff 1 — Memoization vs. No Memoization
Trading O(n) extra space (the memo dictionary) to reduce time from O(2ⁿ) to O(n). For n=50, this is the difference between computing instantly vs. requiring decades of computation.
Tradeoff 2 — Prefix Sum for Range Queries
Without prefix sum: each range sum query is O(k) where k is the range length. With prefix sum: O(n) preprocessing + O(n) extra space → O(1) per query forever after.
For applications with millions of range queries, this tradeoff is highly favorable.
Tradeoff 3 — In-Place Sort vs. Stable Merge Sort
Heap Sort
Time: O(n log n) — same as Merge Sort
Space: O(1) — in-place
Stable: No (can change relative order of equal elements)
Merge Sort
Time: O(n log n) — same as Heap Sort
Space: O(n) — needs auxiliary array
Stable: Yes (preserves relative order of equal elements)
If you need a stable sort (e.g., sorting a list of records where equal-key records must maintain their original relative order), you must use Merge Sort or another stable sort, accepting the O(n) space cost.
Space Complexity Reference Table
| Algorithm | Auxiliary Space | Source of Space |
|---|---|---|
| Linear Search | O(1) | Only index variable |
| Binary Search (iterative) | O(1) | Only index variables |
| Binary Search (recursive) | O(log n) | Recursion stack |
| Bubble Sort | O(1) | Only swap variables |
| Selection Sort | O(1) | Only index variables |
| Insertion Sort | O(1) | Only index variables |
| Merge Sort | O(n) | Temporary merge array |
| Quick Sort (avg) | O(log n) | Recursion stack (balanced) |
| Quick Sort (worst) | O(n) | Recursion stack (unbalanced) |
| Heap Sort | O(1) | In-place heap operations |
| BFS (breadth-first search) | O(n) | Queue holding nodes |
| DFS (depth-first search) | O(h) | Stack (h = tree height) |
| Hash Map operations | O(n) | Hash map storage |
| DP (2D table) | O(m×n) | DP table |
| DP (space-optimized) | O(n) | Single row/array |
Interview Tips for Space Complexity
1. Always state both time and space complexity when presenting a solution.
2. When asked "can you optimize space?", look for:
- Can recursion be converted to iteration? (eliminates O(n) or O(log n) stack space)
- Does the DP table only use the previous row? (reduce 2D to 1D)
- Can you reuse the input array? (achieve O(1) space)
- Is there a mathematical formula that avoids storing results? (avoid O(n) cache)
3. Mention stack overflow risk for deep recursion:
4. Know the space tradeoff for common patterns:
- Hash Map: O(n) space for O(1) lookup vs. O(1) space for O(n) lookup (linear scan)
- Sorted array: O(n log n) preprocessing for O(log n) search vs. O(n) unsorted search
- Memoization: O(n) space for O(n) time vs. O(n) recursive stack for O(2ⁿ) time
Summary
- Space complexity measures auxiliary memory — extra space beyond the input.
- O(1): Only fixed-size variables. In-place algorithms. Best for memory.
- O(log n): Balanced recursion (binary search recursive, quick sort best case).
- O(n): Proportional extra space (merge sort buffer, hash maps, DP arrays).
- O(n²): 2D DP tables (often optimizable to O(n) by keeping only needed rows).
- Recursion creates implicit stack space = O(depth of recursion).
- Time-space tradeoffs are fundamental: memoization, prefix sums, and indexing structures trade memory for speed.
- Iterative algorithms are almost always more space-efficient than recursive equivalents.
- Balanced data structures guarantee O(log n) height and thus O(log n) space for tree operations.
*Next Lesson: Time Complexity Examples — Practice applying all complexity analysis techniques to a wide variety of code patterns and algorithms.*
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for Space Complexity — Memory Analysis, Auxiliary Space, and Time-Space Tradeoffs.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this Data Structures & Algorithms topic.
Search Terms
data-structures-algorithms, data structures & algorithms, data, structures, algorithms, algorithm, analysis, space
Related Data Structures & Algorithms Topics