Table of Content
Problem statement
Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
Example
Input
Straightforward solution
Time Complexity: O(N^2)
Space Complexity: O(1)
So the objective here is go through the given array, nums
, and find two numbers inside such that they add up to a given sum. Immediately, we know that we have to iterate through the array. Because we cannot use the same element twice, we need to look for two different elements in the array that adds up to the given target. The easiest way to do this would be to:
- Iterate through the array.
- Use the current element as one of the two required numbers.
- Pick another element as the second number.
- Check if the current two elements add up to the
target
- If they do, return both of their indices in the array and you’re done.
- If they don’t, then change one of the two elements.
There’s many ways to implement this, but the standard approach is to utilize a doubled for
loop. This approach is easy to understand and is guaranteed to cover all possible 2-combinations of the elements.
- The first
for
loop would start with the1st
element of the array. - The second nested
for
loop would start with the2nd
element of the array since the1st
element is already in use. - If the two numbers don’t add up to the
target
, then the nestedfor
loop will choose the next element, e.g the3rd
element - This ensures that we are going through all combinations of the
1st
element (first for loop) and every element after it (second for loop). - If we still don’t have two numbers adding up to
target
, then we start over by going through all combinations of the2nd
element and every element after it.
Complexity Explanation
Because we’re using two for
loops and one of them is nested, For every one iteration of the outer for loop, we’re performing an iteration of the entire nested for
loop, which is O(N)
. Because worst case, we also have to perform N
iterations for the outer loop, we have to perform N * N
iterations, therefore the time complexity is O(N^2)
.
Since we are not introducing any new data structures, there space complexity is just constant, O(1)
.
Optimized solution
Time Complexity: O(N)
Space Complexity: O(N)
The first solution is not ideal as the time complexity is quadratic. However, we can actually remove our nested for
loop at the expense of using a hash table
as a cache
. Given a number, all we care about is if there’s another number that will add up to the target number. We can perform a first pass through the array and store the number and its index as a key value pair in our hash table
. Then as we iterate through the array, we can subtract the target
from the current number and check if the resulting number exists in our hash table
.
Complexity Explanation
Because now we’re not using a nested for
loop, we’ve effectively reduced our time complexity from O(N^2)
down to O(N)
.
Since we are introducing a hash table
, which can store up to N
key value pairs for this problem. Our space complexity is now O(N)
.
Even more optimized Solution
Time Complexity: O(N)
Space Complexity: O(N)
We can optimize our second solution even further by doing everything in our first pass, effectively eliminating the need for the extra second pass. This approach shares similarity with the sliding window
technique.
Complexity Explanation
Even though we managed to reduce the number of for
loops from 2 to 1, the time complexity is still O(N)
since the constant is ignored in big O notation.
Space complexity stays the same because we’re still using a hash table
for the same purpose.