Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 2

Understanding Space Complexity

Recommended resources

Introduction

In our last lesson, we focused on time complexity, analyzing how the runtime of an algorithm scales with the size of its input. This is a crucial skill for coding interviews, but it's only half of the performance story. An algorithm that is lightning-fast but consumes an enormous amount of memory can be just as problematic as a slow one.

Today, we will complete this foundational picture by tackling the second pillar of complexity analysis: space complexity. You will learn how to determine the amount of memory an algorithm uses and how that memory usage scales with the input size. We'll analyze both iterative and recursive C++ code, paying close attention to the nuances that are important in an interview context.


What is Space Complexity?

Just as time complexity describes the growth rate of an algorithm's runtime, space complexity describes the growth rate of the memory it requires. We use the same Big-O notation to express this relationship.

However, there's an important distinction to make: total space versus auxiliary space.

  • Input Space: The memory used to store the input data itself. For a function that takes a vector of size n, the input space is .
  • Auxiliary Space: The extra or temporary memory that an algorithm uses during its execution. This includes variables, data structures, and the memory used by function calls.
  • Total Space Complexity: The sum of the input space and the auxiliary space.

In coding interviews, when an interviewer asks for the "space complexity," they are most often interested in the auxiliary space. This is the memory you are adding to solve the problem. Let's clarify this with a short video.

Time and Space Complexity - Strivers A2Z DSA Course

Watch this segment from the "Strivers A2Z DSA Course" on the take U forward channel.

Focus on the explanation from this part, where the presenter breaks down space complexity into auxiliary space and input space using a simple example.

The key takeaway is that we analyze the memory our algorithm allocates in addition to the inputs it is given.

To understand where this space is allocated in a C++ program, it helps to have a basic mental model of the two main memory regions: the stack and the heap.

  • The Stack: This is where local variables and function call information are stored. Memory is allocated and deallocated automatically as functions are called and return. It's fast but limited in size.
  • The Heap: This is a large pool of memory used for dynamic allocation (e.g., when you use new in C++ or when containers like std::vector need to grow). You or the container's logic are responsible for managing this memory.
This diagram illustrates how different parts of a C++ program reside in memory. Local variables and function call contexts live on the stack, while dynamically allocated objects (like the string pool or the `Emp` object) are placed on the heap.

Analyzing Iterative Algorithms

Let's start by analyzing the space complexity of some iterative algorithms, which primarily use memory for variables and data structures.

O(1) — Constant Space

An algorithm has constant space complexity if its memory usage does not depend on the input size n. It uses a fixed amount of memory for its variables.

Consider this function that sums the elements of an array:

int sumArray(int arr[], int n) {
    int sum = 0; // O(1) space for 'sum'
    int i = 0;   // O(1) space for 'i'

    for (i = 0; i < n; i++) {
        sum += arr[i];
    }
    return sum;
}

The input arr takes space, but the auxiliary space is constant. We only declare two integer variables, sum and i. Whether the array has 10 elements or 10 million, the memory needed for these two variables remains the same. Therefore, the auxiliary space complexity is . An algorithm with auxiliary space is often called an in-place algorithm.

For more examples of common algorithms with space complexity, you can review the following resource.

Time and Space Complexity: A Beginner's Guide

This article provides a list of common algorithms with their time and space complexity.

Skim through the examples for Linear Search, Bubble Sort, and Palindrome Check. Notice that they all operate directly on the input or use a few fixed variables, resulting in O(1) auxiliary space.

O(n) — Linear Space

Linear space complexity occurs when the amount of auxiliary memory an algorithm needs grows proportionally with the input size n. This often happens when you create a new data structure (like a vector or a map) that stores n elements.

A classic example is counting the frequency of elements in an array. A common approach is to use a hash map (std::unordered_map in C++) to store each unique element and its count.

Time and Space Complexity - GeeksforGeeks

This GeeksforGeeks article provides a solid definition of space complexity and a great example of O(n) space.

First, read the initial definition of space complexity, which introduces the fixed and variable parts of memory usage. Then, examine the C++ code for the frequency counting problem. Pay close attention to the use of unordered_map<int, int> freq;. In the worst case, if all n elements of the input array are unique, this map will store n key-value pairs. Finally, read the explanation that follows. It correctly identifies that the unordered_map (referred to as freq[] array in the text) contributes O(n) to the auxiliary space complexity.


Space Complexity of Recursive Algorithms

When analyzing recursive algorithms, the primary source of auxiliary space is the function call stack. Each time a function calls itself, a new "stack frame" is pushed onto the stack. This frame stores the function's local variables, parameters, and the return address. The space complexity is determined by the maximum number of stack frames present at any one time, which corresponds to the maximum depth of the recursion.

This image visualizes how recursive calls to `fun1` create multiple stack frames, consuming memory on the stack. The depth of recursion directly impacts the space used.

A fantastic video from CodeHelp breaks down the space analysis for several key recursive algorithms.

Lecture 41: Time & Space Complexity of Recursive Algorithms || C++ Placement Course

This video provides a clear, step-by-step analysis of the space complexity for four fundamental recursive algorithms.

Factorial: Watch the analysis from this section. Notice how n nested calls lead to n stack frames, resulting in O(n) space complexity. Binary Search: Next, see the analysis from this part. Because the problem size is halved at each step, the recursion depth is \log n, leading to O(\log n) space. Merge Sort: This one is more subtle. Watch from this segment. The presenter correctly identifies two components: the recursion depth (O(\log n)) and the temporary arrays created for merging. The largest temporary array is of size n, so the total auxiliary space is O(\log n + n), which simplifies to O(n). Fibonacci: Finally, watch the explanation from this clip. Although the recursion tree is very wide, the maximum depth of the call stack at any point is n, leading to O(n) space complexity.


An Important Interview Tip: Don't Modify Your Inputs

It can be tempting to save space by modifying the input array or data structure directly, thus achieving auxiliary space. However, unless the interviewer explicitly allows it, this is generally considered bad practice. In real-world software engineering, the function you write might be part of a larger system where other components depend on the input data remaining unchanged.

This is a sign of good software engineering hygiene that interviewers appreciate. Watch this final clip for a clear explanation of this principle.

Time and Space Complexity - Strivers A2Z DSA Course

The presenter gives a crucial piece of advice for coding interviews.

Watch the segment from this point. The core message is clear: prioritize data integrity over minor space savings by using extra variables or data structures instead of modifying inputs. You can even explicitly state this reasoning to your interviewer.


Conclusion

You now have a complete framework for analyzing the complexity of algorithms in terms of both time and space. This dual understanding is fundamental to designing efficient solutions and is a core expectation in technical interviews.

Key Takeaways:

  • Space Complexity measures how an algorithm's memory usage scales with input size, expressed using Big-O notation.
  • It's critical to distinguish between total space (including inputs) and auxiliary space (extra memory used). Interviewers usually care about auxiliary space.
  • Iterative algorithms use space for variables and data structures. Common complexities are (constant) and (linear).
  • Recursive algorithms use space on the call stack. The space complexity is determined by the maximum recursion depth. This leads to for linear recursion (like factorial) and for divide-and-conquer algorithms like binary search.
  • In an interview, avoid modifying input data unless explicitly told to. It demonstrates good software engineering practice.

In the next lesson, we will add another layer of nuance to our analysis by learning to compare algorithms based on their best-case, worst-case, and average-case complexity, which applies to both time and space.