DSA Tutorial
🔍

Space Complexity

Space Complexity

You've learned that time complexity measures how fast an algorithm runs. But there's another important question: How much memory does it use?

Imagine you're packing for a trip. You could bring everything you own (uses lots of space), or pack only essentials (uses minimal space). Similarly, algorithms can use memory efficiently or wastefully.

Space complexity measures the amount of memory an algorithm needs as the input size grows.

Why Space Complexity Matters

Consider these scenarios:

Scenario 1: Mobile App

  • Limited RAM (2-4 GB)
  • Algorithm using O(n²) space might crash the app
  • Algorithm using O(1) space runs smoothly

Scenario 2: Big Data Processing

  • Processing millions of records
  • O(n) extra space = Gigabytes of RAM needed
  • O(log n) extra space = Minimal RAM needed

Scenario 3: Embedded Systems

  • Microcontrollers with only 2 KB RAM
  • Every byte counts
  • Must use O(1) space algorithms

Key Idea: Space complexity measures how much extra memory an algorithm needs relative to input size.

Total Space vs Auxiliary Space

Total Space Complexity

Total space = Space for input + Space for auxiliary variables

Auxiliary Space Complexity

Auxiliary space = Extra space used by algorithm (excluding input)

Example:

Python
1def sum_array(arr): 2 total = 0 # Extra variable: 1 unit 3 for num in arr: # No extra space 4 total += num 5 return total 6 7# Input space: n (the array) 8# Auxiliary space: O(1) (only 'total' variable) 9# Total space: O(n) (input array + total variable)

Note: We usually focus on auxiliary space because input size is given and constant.

Understanding O(1) Space - Constant Space

Definition: Algorithm uses a fixed amount of extra memory, regardless of input size.

Example 1: Simple Variables

Python
1def find_max(arr): 2 max_val = arr[0] # 1 variable 3 4 for num in arr: 5 if num > max_val: 6 max_val = num # Update same variable 7 8 return max_val 9 10# Extra space: 1 variable (max_val) 11# Space Complexity: O(1)

Analysis:

  • Input size: 10, 100, or 1,000,000 elements
  • Extra variables: Always just 1 (max_val)
  • Space Complexity: O(1)

Example 2: Swap Two Numbers

Python
1def swap(a, b): 2 temp = a # 1 extra variable 3 a = b 4 b = temp 5 return a, b 6 7# Extra space: 1 variable (temp) 8# Space Complexity: O(1)

Understanding O(n) Space - Linear Space

Definition: Extra memory grows proportionally with input size.

Example 1: Copy Array

Python
1def copy_array(arr): 2 new_arr = [] # New array 3 4 for num in arr: 5 new_arr.append(num) # Add to new array 6 7 return new_arr 8 9# Input size: n 10# Extra space: n (new array of same size) 11# Space Complexity: O(n)

Example 2: Reverse Array

Python
1def reverse_array(arr): 2 reversed_arr = [] # New array 3 4 for i in range(len(arr) - 1, -1, -1): 5 reversed_arr.append(arr[i]) 6 7 return reversed_arr 8 9# Input: [1, 2, 3, 4, 5] 10# Output: [5, 4, 3, 2, 1] 11# Extra space: n elements 12# Space Complexity: O(n)

Better Approach: In-Place Reversal (O(1) Space)

Python
1def reverse_in_place(arr): 2 left = 0 3 right = len(arr) - 1 4 5 while left < right: 6 # Swap elements 7 arr[left], arr[right] = arr[right], arr[left] 8 left += 1 9 right -= 1 10 11 return arr 12 13# Extra space: Only 2 variables (left, right) 14# Space Complexity: O(1)

Comparison:

  • First approach: O(n) space, creates new array
  • Second approach: O(1) space, modifies original array
  • Trade-off: Less space but modifies input

Understanding O(n²) Space - Quadratic Space

Definition: Extra memory grows with the square of input size.

Example: 2D Matrix

Python
1def create_matrix(n): 2 matrix = [] 3 4 for i in range(n): 5 row = [] 6 for j in range(n): 7 row.append(i * j) 8 matrix.append(row) 9 10 return matrix 11 12# For n = 3: 13# [[0, 0, 0], 14# [0, 1, 2], 15# [0, 2, 4]] 16# 17# Space: n × n = n² elements 18# Space Complexity: O(n²)

Recursion and Space Complexity

Recursive functions use extra space on the call stack.

Example 1: Factorial (O(n) Space)

Python
1def factorial(n): 2 if n <= 1: 3 return 1 4 return n * factorial(n - 1) 5 6# factorial(5) calls: 7# factorial(5) → factorial(4) → factorial(3) → factorial(2) → factorial(1) 8# 9# Call stack depth: n 10# Space Complexity: O(n) due to recursion stack

Example 2: Iterative Factorial (O(1) Space)

Python
1def factorial_iterative(n): 2 result = 1 3 for i in range(2, n + 1): 4 result *= i 5 return result 6 7# No recursion, no call stack 8# Only one variable: result 9# Space Complexity: O(1)

Comparison:

  • Recursive: O(n) space (call stack)
  • Iterative: O(1) space (just variables)

Common Space Complexities Compared

Space ComplexityExampleMemory for n=100Memory for n=1000
O(1)Finding maxConstantConstant
O(log n)Binary search (recursive)~7 calls~10 calls
O(n)Copying array100 units1,000 units
O(n log n)Merge sort100 × 71,000 × 10
O(n²)2D matrix10,000 units1,000,000 units

Space-Time Trade-offs

Sometimes we can trade space for time, or time for space.

Example: Fibonacci Sequence

Approach 1: Recursive (Slow, Less Space)

Python
1def fibonacci_recursive(n): 2 if n <= 1: 3 return n 4 return fibonacci_recursive(n - 1) + fibonacci_recursive(n - 2) 5 6# Time: O(2^n) - Very slow! 7# Space: O(n) - Call stack depth

Approach 2: Memoization (Fast, More Space)

Python
1def fibonacci_memo(n, memo={}): 2 if n in memo: 3 return memo[n] 4 if n <= 1: 5 return n 6 7 memo[n] = fibonacci_memo(n - 1, memo) + fibonacci_memo(n - 2, memo) 8 return memo[n] 9 10# Time: O(n) - Much faster! 11# Space: O(n) - Store results in dictionary

Approach 3: Iterative (Fast, Minimal Space)

Python
1def fibonacci_iterative(n): 2 if n <= 1: 3 return n 4 5 prev2 = 0 6 prev1 = 1 7 8 for i in range(2, n + 1): 9 current = prev1 + prev2 10 prev2 = prev1 11 prev1 = current 12 13 return prev1 14 15# Time: O(n) - Fast 16# Space: O(1) - Minimal space!

Comparison:

ApproachTimeSpaceTrade-off
RecursiveO(2^n)O(n)Slow, minimal space
MemoizationO(n)O(n)Fast, uses extra space
IterativeO(n)O(1)Fast, minimal space - Best!

How to Calculate Space Complexity

Rule 1: Count Variables

Python
1def example(n): 2 a = 0 # 1 variable 3 b = 0 # 1 variable 4 c = 0 # 1 variable 5 6 for i in range(n): 7 print(a + b + c) 8 9# Space: 3 variables + loop counter 10# Space Complexity: O(1) - constant

Rule 2: Count Data Structures

Python
1def example(n): 2 arr = [0] * n # Array of size n 3 result = 0 # 1 variable 4 5 for num in arr: 6 result += num 7 8# Space: n (array) + 1 (result) 9# Space Complexity: O(n)

Rule 3: Count Recursion Depth

Python
1def count_down(n): 2 if n == 0: 3 return 4 print(n) 5 count_down(n - 1) 6 7# count_down(5) → count_down(4) → count_down(3) → ... 8# Call stack: n levels deep 9# Space Complexity: O(n)

Practice Problems

Problem 1: What's the Space Complexity?

Python
1def mystery(arr): 2 total = 0 3 for i in range(len(arr)): 4 for j in range(len(arr)): 5 total += arr[i] * arr[j] 6 return total 7 8# Answer: O(1) 9# Explanation: Only 'total' variable, loops don't create extra space

Problem 2: Reduce Space Complexity

Given this function, can you reduce its space complexity?

Python
1# Original: O(n) space 2def sum_first_k(arr, k): 3 subset = arr[:k] # Creates new array 4 total = sum(subset) 5 return total 6 7# Improved: O(1) space 8def sum_first_k_optimized(arr, k): 9 total = 0 10 for i in range(k): 11 total += arr[i] 12 return total 13 14# No extra array needed!

Key Takeaways

Space Complexity measures extra memory used by an algorithm.

Auxiliary Space excludes input size (focus on extra variables/structures).

Common Complexities: O(1) < O(log n) < O(n) < O(n²)

Recursion uses O(depth) space for the call stack.

Trade-offs: Sometimes we use more space to get faster time.

In-place algorithms modify input directly to save space (O(1) instead of O(n)).

What's Next?

Now that you understand space complexity:

  1. Asymptotic Analysis - Deep dive into Big-O, Omega, Theta
  2. Array Operations - Apply complexity analysis to arrays
  3. Recursion - Master recursive space complexity

Practice Exercises

Determine the space complexity:

Exercise 1

Python
1def exercise1(n): 2 result = [] 3 for i in range(n): 4 result.append(i * 2) 5 return result 6 7# Answer: O(n) - creates array of size n

Exercise 2

Python
1def exercise2(n): 2 if n <= 0: 3 return 1 4 return n * exercise2(n - 1) 5 6# Answer: O(n) - recursion depth of n

Ready to continue? Let's explore Asymptotic Analysis next!

Space Complexity