Playing Hacks and Stuffs!
Given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
You can return the answer in any order.
The task is that:
We’ll be given an array of numbers and a target value
We are asked to return the index of two numbers from the array whose sum is the target value
Input: nums = [2,7,11,15], target = 9
Output: [0,1]
Explanation: Because nums[0] + nums[1] == 9, we return [0, 1].
At first my thought was that this can be easily solved if the array length is small
Since it would be a brute force sort of solve
And what that will basically do is this!
Consider this array:
nums = [2,7,11,15]
target = 9
In two loops I’ll compare the sum of each values of the array with the target value:
nums[i] + num[j] == target True | False
That would be in a loop of range array.length()
But you can tell that if the length is large then that increases the time complexity since it will perform multiple loops
Here’s a sample script to solve this:
def brute(nums, target):
for i in range(len(nums)):
for j in range(len(nums)):
if nums[i] + nums[j] == target:
return [i, j]
return None
nums = [2,7,11,15]
target = 9
result = brute(nums, target)
print(result)
Running that works
We can submit that on the platform too
But I noticed this error
Well looking at that we can see it failed and that’s True because I forgot the condition:
You may assume that each input would have exactly one solution, and you may not use the same element twice.
We can’t use the same element twice
To solve that part I just add a check in my script to not use the same element and that can be done by starting the second nested loop from i+1
Here’s it
def brute(nums, target):
for i in range(len(nums)):
for j in range(i+1, len(nums)):
if nums[i] + nums[j] == target:
return [i, j]
return None
nums = [3,2,4]
target = 6
result = brute(nums, target)
print(result)
Submitting it finally worked!
But looking at the Runtime and Memory it used we can see that this isn’t a good approach
So I decided to try a better way of solving this
I tried to implement using Binary Search
And here’s the explanation
Consider this array and target value:
nums = [9,3,1,4,5,2,8,6,10,7]
target = 6
For we to work with Binary Search the array needs to be sorted
So I’ll sort it out, get the left & right value and take the sum of the value in the left sorted array with the right last value
>>> nums = [9,3,1,4,5,2,8,6,10,7]
>>> target = 6
>>>
>>> array = sorted(nums)
>>> left = 0
>>> right = len(array) - 1
>>> sum = array[left] + array[right]
>>> sum
11
>>>
We can see that the sum is greater than the target value, so we’ll move the search space to the left by 1
>>> right -= 1
>>> sum = array[left] + array[right]
>>>
>>> sum
10
>>>
The sum is greater than the target so I’ll move the search space to the left by 1
>>> right -= 1
>>> sum = array[left] + array[right]
>>>
>>> sum
9
>>>
Basically we’ll keep on going till we get this
>>> right -= 1
>>> sum = array[left] + array[right]
>>>
>>> sum
6
>>>
At this point the sum is equal to the target value
Now we’ll get the value of array[left] & array[right]
>>> array[left]
1
>>> array[right]
5
>>>
Because the array has been sorted we’ll need to get it’s corresponding index from the original array
We can just use python index()
function to do this
>>> nums.index(1)
2
>>> nums.index(5)
4
>>>
Cool the index is [2, 4]
and that will be our answer
To confirm we can sum the values of nums[2]
and nums[4]
and we know it will return 6
becasue it’s value is 2 & 4
>>> nums[2] + nums[4]
6
>>>
That’s the solution!
So I wrote a script to implement this
def twoSum(nums, target):
array = sorted(nums)
left, right = 0, len(array) - 1
result = []
while left <= right:
sum = array[left] + array[right]
if sum == target:
result.append(nums.index(array[left]))
result.append(nums.index(array[right]))
return result
elif sum > target:
right -= 1
else:
left += 1
return None
nums = [9,3,1,4,5,2,8,6,10,7]
target = 6
result = twoSum(nums, target)
print(result)
It works but then I saw an issue
If I run it against this test case it doesn’t return the right value
Input: nums = [3,3], target = 6
Output: [0,1]
I spent some time trying to fix that but failed 😢
So after looking through the Editorial I saw they used a more faster algorithm Two-pass Hash Table
Algorithm:
A simple implementation uses two iterations. In the first iteration, we add each element’s value as a key and its index as a value to the hash table. Then, in the second iteration, we check if each element’s complement target - nums[i]
exists in the hash table. If it does exist, we return current element’s index and its complement’s index. Beware that the complement must not be nums[i]
itself!
Let me explain it:
Consider this array of numbers:
nums = [9,3,1,4,5,2,8,6,10,7]
target = 11
First we’ll iterate through the values in the nums array taking it’s complement and keeping the progress in a dictionary defined as this: {integer: index}
11 - 9 = 2
Our hash table dictionary will be this:
{9: 0}
We go over the second index
11 - 3 = 8
Hash table dictionary
{3: 1}
During this iteration we’ll check if the current complement is in the hash table dictionary
if complement in hashtable:
If that returns True that means we’ve found a number that meets the condition required for this task
And we’ll return the index of the position of the current complement with the iterate
[hashtable[complement], i]
With that said I made a script to do that
def twoSum(nums, target):
hashtable = {}
for i, j in enumerate(nums):
complement = target - j
if complement in hashtable:
return [hashtable[complement], i]
hashtable[j] = i
return None
nums = [2,7,11,15]
target = 17
result = twoSum(nums, target)
print(result)
Submitting it we can see it works pretty good
In terms of speed it was way faster but in memory it is consumes some amount of memory and that’s because each iterate is stored in the dictionary
That’s all!