← Back to DSA Course | Chapter 1: Introduction & Complexity | Lesson 3 of 6

Space Complexity

What is Space Complexity

Space complexity measures how much extra memory an algorithm needs as its input grows, expressed the same way as time complexity using Big O. It matters just as much as speed when you're working with large datasets or memory-constrained environments like embedded devices.

Example: What is Space Complexity

#include <iostream>
using namespace std;
int main() {
    int n = 5;
    int arr[5]; // extra memory grows with n: O(n) space
    for (int i = 0; i < n; i++) arr[i] = i * i;
    cout << "arr[4]: " << arr[4] << " (O(n) extra space)" << endl;
    return 0;
}
public class Main {
    public static void main(String[] args) {
        int n = 5;
        int[] arr = new int[n]; // extra memory grows with n: O(n) space
        for (int i = 0; i < n; i++) arr[i] = i * i;
        System.out.println("arr[4]: " + arr[4] + " (O(n) extra space)");
    }
}
n = 5
arr = [i * i for i in range(n)]  # extra memory grows with n: O(n) space
print("arr[4]:", arr[4], "(O(n) extra space)")
#include <stdio.h>
int main() {
    int n = 5;
    int arr[5]; /* O(n) extra space */
    for (int i = 0; i < n; i++) arr[i] = i * i;
    printf("arr[4]: %d (O(n) extra space)\n", arr[4]);
    return 0;
}

Auxiliary Space

Auxiliary space is the extra memory an algorithm allocates beyond the input itself, such as a temporary array, a hash map, or recursion's call stack. Two algorithms that both run in O(n) time can differ hugely in auxiliary space, which is often the real deciding factor between them.

Example: Auxiliary Space

#include <iostream>
using namespace std;
int main() {
    int input[] = {5, 3, 1, 4};
    int n = 4;
    int temp[4]; // auxiliary array beyond the input itself
    for (int i = 0; i < n; i++) temp[i] = input[i] * 2;
    cout << "temp[2]: " << temp[2] << " (auxiliary O(n) space)" << endl;
    return 0;
}
public class Main {
    public static void main(String[] args) {
        int[] input = {5, 3, 1, 4};
        int[] temp = new int[4]; // auxiliary array beyond the input itself
        for (int i = 0; i < 4; i++) temp[i] = input[i] * 2;
        System.out.println("temp[2]: " + temp[2] + " (auxiliary O(n) space)");
    }
}
input_arr = [5, 3, 1, 4]
temp = [x * 2 for x in input_arr]  # auxiliary list beyond the input itself
print("temp[2]:", temp[2], "(auxiliary O(n) space)")
#include <stdio.h>
int main() {
    int input[] = {5, 3, 1, 4};
    int temp[4]; /* auxiliary array beyond the input itself */
    for (int i = 0; i < 4; i++) temp[i] = input[i] * 2;
    printf("temp[2]: %d (auxiliary O(n) space)\n", temp[2]);
    return 0;
}

Space in Loops

A loop that just tracks a running total, a counter, or a single swapped value uses O(1) constant space no matter how large the input is, because it never allocates new storage proportional to n. That's why in-place algorithms are prized when memory is tight.

Example: Space in Loops

#include <iostream>
using namespace std;
int main() {
    int arr[] = {1, 2, 3, 4, 5};
    int total = 0; // just one variable: O(1) space, no matter arr size
    for (int i = 0; i < 5; i++) total += arr[i];
    cout << "Total: " << total << " (O(1) space)" << endl;
    return 0;
}
public class Main {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4, 5};
        int total = 0; // O(1) space, no matter arr size
        for (int x : arr) total += x;
        System.out.println("Total: " + total + " (O(1) space)");
    }
}
arr = [1, 2, 3, 4, 5]
total = 0  # O(1) space, no matter list size
for x in arr:
    total += x
print("Total:", total, "(O(1) space)")
#include <stdio.h>
int main() {
    int arr[] = {1, 2, 3, 4, 5};
    int total = 0; /* O(1) space */
    for (int i = 0; i < 5; i++) total += arr[i];
    printf("Total: %d (O(1) space)\n", total);
    return 0;
}

Recursion and Space

Every recursive call pushes a new frame onto the call stack to remember its local variables and where to return to, so a recursion that goes n levels deep uses O(n) space even if it does no other allocation. This is a common reason recursive solutions can hit stack overflow errors that their iterative equivalents wouldn't.

Example: Recursion and Space

#include <iostream>
using namespace std;
int sumTo(int n) {
    if (n == 0) return 0; // each call stays on the stack: O(n) space
    return n + sumTo(n - 1);
}
int main() {
    cout << "sumTo(5): " << sumTo(5) << " (O(n) stack space)" << endl;
    return 0;
}
public class Main {
    static int sumTo(int n) {
        if (n == 0) return 0; // O(n) stack space
        return n + sumTo(n - 1);
    }
    public static void main(String[] args) {
        System.out.println("sumTo(5): " + sumTo(5) + " (O(n) stack space)");
    }
}
def sum_to(n):
    if n == 0:
        return 0  # O(n) stack space
    return n + sum_to(n - 1)

print("sum_to(5):", sum_to(5), "(O(n) stack space)")
#include <stdio.h>
int sumTo(int n) {
    if (n == 0) return 0; /* O(n) stack space */
    return n + sumTo(n - 1);
}
int main() {
    printf("sumTo(5): %d (O(n) stack space)\n", sumTo(5));
    return 0;
}

Memory Choices

Good algorithm design usually means trading time for space or vice versa: caching results can speed up an algorithm at the cost of memory, while an in-place approach saves memory but may need more careful, sometimes slower, logic. Recognizing this trade-off is a core DSA skill.

Example: Memory Choices

#include <iostream>
using namespace std;
int main() {
    int arr[] = {5, 1, 4, 2};
    int n = 4;
    // In-place swap: saves memory (O(1) space), no extra array needed.
    for (int i = 0; i < n / 2; i++) {
        int tmp = arr[i];
        arr[i] = arr[n - 1 - i];
        arr[n - 1 - i] = tmp;
    }
    cout << "Reversed[0]: " << arr[0] << endl;
    return 0;
}
public class Main {
    public static void main(String[] args) {
        int[] arr = {5, 1, 4, 2};
        int n = 4;
        // In-place swap: O(1) space, no extra array needed.
        for (int i = 0; i < n / 2; i++) {
            int tmp = arr[i];
            arr[i] = arr[n - 1 - i];
            arr[n - 1 - i] = tmp;
        }
        System.out.println("Reversed[0]: " + arr[0]);
    }
}
arr = [5, 1, 4, 2]
arr.reverse()  # in-place: O(1) extra space, no new list built
print("Reversed[0]:", arr[0])
#include <stdio.h>
int main() {
    int arr[] = {5, 1, 4, 2};
    int n = 4;
    /* In-place swap: O(1) space, no extra array needed. */
    for (int i = 0; i < n / 2; i++) {
        int tmp = arr[i];
        arr[i] = arr[n - 1 - i];
        arr[n - 1 - i] = tmp;
    }
    printf("Reversed[0]: %d\n", arr[0]);
    return 0;
}
🔒

Chapter Quiz — Complete all 6 topics to unlock

0/6 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.