Table of contents
The Two Sum problem in Leetcode might seem tricky in the beginning, but it's fairly easy once you understand the logic. Of course, there are many ways to solve the problem, and we're going to discuss two approaches - brute force & an optimized solution using a hashmap.
Understanding the problem
The question basically states that you have an array of numbers and a target, and you want to return the index of two numbers from the array that sum to be equal to the target. One important thing to note here is that the question says there's only one valid answer.
If you haven't understood the question from the description, let's walk through the first example given on Leetcode to understand it better.
//Example 1
Input: nums = [2,7,11,15], target = 9
Output: [0,1]
Looking at this example, it's clear that the only way you can get a sum of 9 is by adding 2 and 7, which have the indexes 0 and 1 respectively, and that is what we need to return. Similarly, if the target were 13, we know that the only way to get that is by adding 2 and 11, and in that case, the output would have to be [0,2].
And if none of the integers in the array add up to the target, we can just return an empty array, i.e., [].
The Solution
Your first intuition might be to just use 2 loops to loop through the array twice to see if you can find the "complement" number in the array, like so:
var twoSum = function(nums, target) {
for(let i=0; i<nums.length; i++){
for(let j=i+1; j<nums.length; j++){
if(nums[j]===target-nums[i]){
return [i, j]
}
}
}
return null
}
If you're having difficulty visualizing this code, let's try to work through the example that we used above, where the target is 9.
i | j | nums[j] | target-nums[i] |
0 | 1 | 7 | 9 - 2 = 7 |
Since both the target and the complement (target-nums[i]) are equal, we simply return the indexes i and j, and that's it - you'll pass all the test cases on Leetcode. However, this isn't the most efficient way of solving this problem since the time complexity is O(n<sup>2</sup>)
(because we loop through the array twice). A more efficient way of solving this problem is with hashmaps.
A More Optimized Approach
Using a hashmap, you can reduce the time complexity to O(n). The way the hashmap approach works is that at every iteration of the loop, we calculate the difference between the current element and the target (or the complement of the number you're on). Then, we check if this difference exists as the key in the hashmap. If it does, we'll return the value that corresponds to this key, which is the index of the previously seen element, and the current value of i, which corresponds to the current element. If the difference doesn't exist as a key, we're going to store the current element of the array as the key and the index i as its value.
You can think of hashmap as a store of what we've already "seen". Consider again the example given above. If we are at the first value, i.e., 2, and it's not part of the map yet, we'll just add it as a key with its index as its value (since we need some way to store the indexes so that we can return them later). So after the first iteration, the map will be map{2:0}
. Then, when the loop runs a second time at i=1, the difference then becomes 2, and since we already have 2 in our map, we just need to return its index, i.e., the value corresponding to map[2] and i, the current value of the iteration.
I'm sure this sounds confusing right now, but this table can make things a little clearer:
i | nums[i] | diff = target - nums[i] | map |
0 | 2 | 9-2=7 | {2:0} |
1 | 7 | 9-7 = 2 | {2:0} |
In the first iteration, map[diff] or map[7] is undefined, so we'll add nums[i] to the map with the index as our first "seen" object. Then in the next iteration, since the difference exists in our map (is not undefined and has been "seen"), we'll return [map[diff], i]
which turns out to be [0,1]
. And if no two numbers add up to the target, we'll just return an empty array.
If we convert all of this into code, we get:
var twoSum = function(nums, target) {
let map = {}
for(let i=0; i<nums.length; i++){
let diff = target - nums[i]
if(map[diff]!==undefined){
return [map[diff], i]
}
map[nums[i]]=i
}
return []
};
Since we traverse the list with n elements only once and each lookup only costs O(1) time, making our time complexity O(n).
And that's pretty much all there is to this question. As always, you can find the code on my GitHub or you can run it directly on OneCompiler.
Solving Leetcode problems is hard enough as it is, and add to that the difficulty of finding an in-depth solution that explains everything, and you find yourself stuck. Some videos are hard to follow, some don't explain the basics, while others leave you with more questions than answers. In this series, I break down Leetcode problems one at a time and walk you through a step-by-step solution. Have a question you can't understand? Send it to me, and I'll explain it in detail. And don't forget to subscribe to my newsletter to get my articles directly into your inbox!