Space Complexity measures the total amount of memory that an algorithm or operation needs to run according to its input size.
Space Complexity is a parallel concept to Time Complexity. We express space complexity measurements using the Big-O notation, following the same guidelines like we do for time complexity.
Now let's learn how to compute space complexity by taking a few examples:
Constant Space Complexity:
function sum(a, b) {
let sum = a + b;
return sum;
}
In the example above, we use 3 number variables: a
and b
, which are input variables and sum
, which is an auxiliary variable.
And because the space requirement is fixed (3 number variables), hence it is called Constant Space Complexity and is noted with O(1)
.
Linear Space Complexity:
function generate(n) {
let numbers = [];
for (let i = 0; i < n; i++) {
numbers.push(i);
}
return numbers;
}
In the example above, we use an auxiliary array numbers which is populated with n numbers.
Since the total space requirement is n numbers, the Space Complexity is increasing linearly with the increase in the input value n, hence it is called as Linear Space Complexity and is noted with O(n)
.
Quadratic Space Complexity:
function generate(n) {
let numbers = [];
for (let i = 0; i < n; i++) {
numbers.push([]);
for (let j = 0; j < n; j++) {
numbers[i].push(j);
}
}
return numbers;
}
In the example above, we use an auxiliary 2D array numbers of n rows and n columns.
Since the total space requirement is n^2 numbers, the Space Complexity is directly proportional to the squared of the input value n, hence it is called as Quadratic Space Complexity and is noted with O(n^2)
.
Extra/Auxiliary Space:
Sometimes Extra/Auxiliary Space is confused with Space Complexity. But Auxiliary Space is the extra space or the temporary space used by the algorithm during its execution (without taking the input values into account).
Space Complexity = Auxiliary Space + Input space
Let's see some examples:
function sum(arr) {
let sum = 0;
for(let num of arr) {
sum += num;
}
return sum;
}
In the example above, we have an input array arr. If we denote its length by n, the Input Space is O(n)
.
However, we use only 2 auxiliary variables sum and num, so the Extra Space is O(1)
.
The core challenge of understanding space complexity lies in recognizing how much memory an algorithm uses relative to its input size. This is crucial for optimizing programs, especially when dealing with large datasets or limited memory environments.
Common applications include optimizing algorithms for embedded systems, mobile applications, and large-scale data processing where memory usage is a critical factor.
Potential pitfalls include confusing space complexity with time complexity and not accounting for all auxiliary space used by the algorithm.
To solve problems related to space complexity, follow these steps:
Let's discuss a naive approach and its limitations:
Consider a function that sums the elements of an array:
function naiveSum(arr) {
let sum = 0;
for(let i = 0; i < arr.length; i++) {
sum += arr[i];
}
return sum;
}
This function has a space complexity of O(n)
due to the input array, but the auxiliary space is O(1)
. This is efficient, but let's consider a more complex example:
For a more complex example, consider generating a 2D array:
function generate2DArray(n) {
let array = [];
for (let i = 0; i < n; i++) {
array.push([]);
for (let j = 0; j < n; j++) {
array[i].push(j);
}
}
return array;
}
Step-by-step breakdown:
This algorithm has a space complexity of O(n^2)
due to the 2D array.
Here is the code for the discussed algorithms:
// Constant Space Complexity: O(1)
function sum(a, b) {
let sum = a + b;
return sum;
}
// Linear Space Complexity: O(n)
function generate(n) {
let numbers = [];
for (let i = 0; i < n; i++) {
numbers.push(i);
}
return numbers;
}
// Quadratic Space Complexity: O(n^2)
function generate2DArray(n) {
let array = [];
for (let i = 0; i < n; i++) {
array.push([]);
for (let j = 0; j < n; j++) {
array[i].push(j);
}
}
return array;
}
// Extra/Auxiliary Space Example
function sumArray(arr) {
let sum = 0;
for(let num of arr) {
sum += num;
}
return sum;
}
Let's analyze the time and space complexity of each approach:
O(1)
- Fixed space usage regardless of input size.O(n)
- Space usage grows linearly with input size.O(n^2)
- Space usage grows quadratically with input size.O(1)
- Fixed auxiliary space, input space is O(n)
.Comparing these complexities helps in understanding the trade-offs between different solutions.
Consider the following edge cases:
Testing for these edge cases ensures robustness of the algorithm.
To test the solutions comprehensively:
Here are some tips to approach and think about such problems:
Understanding space complexity is crucial for optimizing algorithms, especially in memory-constrained environments. By analyzing and comparing different approaches, we can design more efficient solutions.
Practice and exploration are key to mastering these concepts. Keep challenging yourself with new problems and refining your skills.
For further reading and practice problems, consider the following resources:
Our interactive tutorials and AI-assisted learning will help you master problem-solving skills and teach you the algorithms to know for coding interviews.
Start Coding for FREE