Skip to content
Laviyx Learn

Try

DSA course menu

Space Complexity Explained (With Python Examples)

Learn space complexity: how much extra memory an algorithm needs, in-place versus extra-space solutions, the memory cost of recursion, and the time-memory trade-off.

Beginner6 min readUpdated
On this page

Space complexity describes how much extra memory an algorithm needs as the input grows. It uses the same Big O notation as time.

We usually count only the auxiliary space: memory the algorithm creates itself, not the input it was given.

O(1) space: a few variables#

Python
def find_max(items):
    best = items[0]          # one variable
    for x in items:
        if x > best:
            best = x
    return best

print(find_max([3, 17, 8, 21, 5]))
Output
21

However long the list is, the function only ever keeps best and x. That is O(1) extra space.

O(n) space: building something as big as the input#

Python
def squares(items):
    result = []
    for x in items:
        result.append(x * x)   # result grows to n items
    return result

print(squares([1, 2, 3, 4]))
Output
[1, 4, 9, 16]

The new list has one entry per input item: O(n) space.

In-place algorithms#

An in-place algorithm changes the input directly instead of building a copy. Reversing a list both ways:

Python
def reversed_copy(items):
    return items[::-1]               # new list: O(n) space

def reverse_in_place(items):
    left, right = 0, len(items) - 1
    while left < right:              # O(1) space: two indexes
        items[left], items[right] = items[right], items[left]
        left += 1
        right -= 1

data = [1, 2, 3, 4, 5]
print(reversed_copy(data), data)
reverse_in_place(data)
print(data)
Output
[5, 4, 3, 2, 1] [1, 2, 3, 4, 5]
[5, 4, 3, 2, 1]

The copy leaves data unchanged but needs n extra slots. The in-place version needs only two indexes, but it modifies the caller's list. Which one is right depends on whether the caller still needs the original.

Recursion uses memory too#

Every recursive call waits on the call stack until the calls below it return. A recursion that goes n levels deep uses O(n) space, even with no lists in sight:

Python
import sys

def depth(n):
    if n == 0:
        return 0
    return 1 + depth(n - 1)

print(depth(500))
print("Python's default recursion limit:", sys.getrecursionlimit())
Output
500
Python's default recursion limit: 1000

Asking for depth(5000) would raise RecursionError, because Python stops the stack at its limit. A loop that does the same counting needs O(1) space. More on this in Recursion.

The time-memory trade-off#

Spending memory often saves time. Answering "how many times does each word appear?" for many queries:

Python
text = "the cat and the hat and the bat"
words = text.split()

# Option 1: no extra memory, O(n) per question
print(words.count("the"))

# Option 2: O(n) memory once, then O(1) per question
counts = {}
for w in words:
    counts[w] = counts.get(w, 0) + 1
print(counts["the"], counts["and"])
Output
3
3 2

If you ask one question, counting directly is fine. If you ask thousands, building the dictionary once is far faster overall.

Common mistakes#

Practice#

Practice exercise

Write running_total(items) that replaces each item with the sum of itself and all items before it, in place, using O(1) extra space. For [1, 2, 3, 4] the list should become [1, 3, 6, 10].

Show hint

Go from left to right. Each item becomes itself plus the (already updated) item before it.

Show solution
Python
def running_total(items):
    for i in range(1, len(items)):
        items[i] += items[i - 1]

data = [1, 2, 3, 4]
running_total(data)
print(data)
Output
[1, 3, 6, 10]

Only the loop variable i is created, so the extra space is O(1); the time is O(n). This idea, a prefix sum, gets its own lesson in Prefix Sums.

Key takeaway#

Next: functions that call themselves, in Recursion.

Finished this lesson?