This blog aims to using one single method to solve the Nsum question.
The two sum question could have mutiple solutions as its requirement is quite simple compered with other sum questions. Especially the question has mention there is an exactly one solution and require to return the index thus using a hash map would be more efficient here as it is not related to the duplicate removal situation which we would see later. Here are the hash map solution.
num_dict = dict()
for i,n in enumerate(nums):
difference = target - n
if difference in num_dict:
return [num_dict[difference],i]
num_dict[n] = i
return
As for 3sums, a fundamental difference is that it needs to return the elements of the array that sums up equal to zero (target), a straightforward idea could be a Brute-force method to have a triple nested for loop to get all the element combination that is sumed up as 0 and put it in a set (to avoide duplicate) then return the set. But it will lead to a O(n3) which is very less efficient.
class Solution(object):
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
nums.sort()
result = []
for i in range(len(nums)):
if i > 0 and nums[i]==nums[i-1]:
continue
l = i+1
r = len(nums)-1
while l<r:
if nums[i] + nums[l] + nums[r] > 0:
r-=1
elif nums[i] + nums[l] + nums[r] < 0:
l+=1
elif nums[i] + nums[l] + nums[r] == 0:
result.append([nums[i],nums[l],nums[r]])
while l < r and nums[l] == nums[l+1]:
l+=1
while l < r and nums[r] == nums[r-1]:
r-=1
l+=1
r-=1
return result
By using two pointers method, for 3 sum question, we only need one for loop nest with while loop, which is O(n2). we can imagine it to be using the for loop to determine the first element, then for the rest two pointer, it is similar to the two sum problem. We have use sorting here, to ensure we skip the uncessary step, otherwise we don't know if we've skiped the result. If we don't use the sorting, the element is disordered,then to get the right answer we have to use the Brute-force.
By this idea, 4 sum problem could be reduced as a nested for loop + two sum problem. Which is O(n3) comapre with O(n4) with Brute-force.
class Solution(object):
def fourSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[List[int]]
"""
nums.sort()
result = []
for i in range(len(nums)):
if i >0 and nums[i] == nums[i-1]:
continue
for k in range(i+1,len(nums)):
if k >i+1 and nums[k] == nums[k-1]:
continue
l = k+1
r = len(nums)-1
while l < r:
if nums[i]+nums[k]+nums[l]+nums[r] > target:
r -= 1
elif nums[i]+nums[k]+nums[l]+nums[r] < target:
l += 1
elif nums[i]+nums[k]+nums[l]+nums[r] == target:
result.append([nums[i],nums[k],nums[l],nums[r]])
while l < r and nums[l] == nums[l+1]:
l += 1
while l < r and nums[r] == nums[r-1]:
r -= 1
l += 1
r -= 1
return result
Another key points here is to remove the duplicate. Imagine nums = [0,0,1,1,2,3,4,5,5], target is 6, we may have duplicate answer like[0,0,1,5],[0,0,1,5],[0,0,2,4]. The solution is when we find the answer first time, that is nums[i]+nums[k]+nums[l]+nums[r] == target, we add the answer into the result. Then, as we have sorted, if nums[l] == nums[l+1], which means if we don't change, the next round of the while loop may receive a duplicate result, so we need to move forward until l+1 is not equal to l. Same with r pointer, and also the selection of element(i and k).