I felt like doing an algorithm and found this problem on leetcode
Given an array of integers, find two numbers such that they add up to a specific target num
The naïve solution to the two-sum problem is O(n^2)
, s.t. n
is the length of the array of numbers provided.
However, we can do better by using a hash-map of the values seen so far (key=number, value=index) and checking if the complement is already there (O(1)
) as we iterate over the numbers. This approach is optimal for an unsorted array:
O(n)
O(n)
-- though if there is a solution, in practice this would be O(n/2)
Given the OP's question:
O(n)
) or time (O(n)
), depending on the approach chosen. Therefore, the 1st part of the (currently) accepted solution is, strictly speaking, incorrect.Optimal solution:
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
seen = {}
for j, num in enumerate(nums):
i = seen.get(target-num, -1)
if i != -1:
return [i+1, j+1]
seen[num] = j
return [-1, -1]
import java.util.Map;
import java.util.HashMap;
public class Solution {
public int[] twoSum(int[] nums, int target) {
final Map<Integer, Integer> seen = new HashMap<>();
for (int j = 0; j < nums.length; ++j) {
final Integer i = seen.get(target - nums[j]); // One hash-map access v.s. two when using contains beforehand.
if (i != null) {
return new int[]{ i+1, j+1 };
}
numbers.put(nums[j], j);
}
return new int[]{-1, -1};
}
}
Note that by construction, if the complement is present in the map/dictionary, then the index stored will always be lower than the current index. Hence the following proposition is verified:
index1 must be less than index2
Also note that the OP's question needed 1-based indexes, which is what I've provided above, but the Leetcode question referred to seems to have been updated since then, and now is 0-based: https://leetcode.com/problems/two-sum.
I hope this helps.
Here is an Efficient Solution.
Time Complexity - O(n) and Space Complexity - O(1)
Sol: Will take two-pointer(start_pointer and end_pointer). Initially start_pointer point at the first index and end_pointer point to the last.
Add both the element (sum = array[start_pointer] + array[last_pointer]. After that check, if the sum > target element or not. If yes decrease the end_pointer else increase start_pointer. If sum = target, means you got the indexes.
public int[] twoSum(int[] numbers, int target) {
int[] arr = new int[2]; // to store result
int sum=0;
int start_pointer=0;
int end_pointer = (numbers.length)-1;
while(start_pointer<=end_pointer){
sum=numbers[start_pointer]+numbers[end_pointer];
if(sum>target)
end_pointer-=1;
else if(sum<target)
start_pointer+=1;
else{
arr[0]=start_pointer;
arr[1]=end_pointer;
break;
}
}
return arr;
}
public static int[] twoSum(int[] nums, int target) {
int []resultarray=new int[2];
for (int i=0;i<nums.length-1;i++){
for(int k=1;k<nums.length;k++)
{
if(target==nums[i]+nums[k])
{
resultarray[0]=nums[i];
resultarray[1]=nums[k];
}
}
}
return resultarray;
}
This is my python solution
class Solution:
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
copy_dict = {}
for pos in range(0, len(nums)):
if nums[pos] not in copy_dict.keys():
copy_dict[nums[pos]] = [pos]
else:
copy_dict[nums[pos]].append(pos)
def get_sum_indexes(sorted_array, target):
right_pointer = len(sorted_array) - 1
left_pointer = 0
while left_pointer < len(sorted_array) or right_pointer > 0:
if sorted_array[right_pointer] + sorted_array[left_pointer] == target:
return [sorted_array[left_pointer], sorted_array[right_pointer]]
elif sorted_array[right_pointer] + sorted_array[left_pointer] > target:
right_pointer -= 1
elif sorted_array[right_pointer] + sorted_array[left_pointer] < target:
left_pointer += 1
return None
sum_numbers = get_sum_indexes(sorted(nums), target)
if len(copy_dict[sum_numbers[0]]) == 1:
answer_1 = copy_dict[sum_numbers[0]][0]
else:
answer_1 = copy_dict[sum_numbers[0]][0]
if len(copy_dict[sum_numbers[1]]) == 1:
answer_2 = copy_dict[sum_numbers[1]][0]
else:
answer_2 = copy_dict[sum_numbers[1]][1]
return sorted([answer_1, answer_2])
print(Solution().twoSum(nums=[-1, -2, -3, -4, -5], target=-8))
print(Solution().twoSum(nums=[-3, -3], target=-6))
Swift code with Time Complexity O(n) and Space complexity O(n):
import UIKit
class Solution{
func twoSum(_ nums: [Int], _ target: Int) -> [Int]{
var finalArray = [Int]()
var newDictionary = [Int:Int]()
for i in 0..<nums.count{
let complement = target - nums[i]
if newDictionary[complement] != nil && newDictionary[complement] != i{
finalArray.append(newDictionary[complement]!)
finalArray.append(i)
return finalArray
}
newDictionary[nums[i]] = i
}
return []
}
}
func main(){
let solution = Solution()
print("All Good" ,solution.twoSum([1, 3, 4 , 5], 6))
}
main()
I tried most of the answers and they don't seem to handle the edge cases properly. Hence, throwing my two cents for python3 solution that handles the edge cases. I used Max's algorithm to implement it:
def twoSum(nums, target):
output=[]
arr=sorted(nums)
x=0
y=-1
X=len(nums)-1
while x<X:
if (arr[X]+arr[x] > target):
X-=1
elif (arr[X]+arr[x] < target):
x+=1
elif (arr[X]+arr[x] == target):
#print("Found",arr[X],arr[x])
num1=arr[x]
num2=arr[X]
x+=1
X-=1
for i in range(len(nums)):
if num1 == nums[i] and y==-1:
index1=i
y=i
elif num2 == nums[i]:
index2=i
return [index1, index2]
N.B. It's important to consider edge cases and inputs like the following
print(twoSum([3,2,4], 6)) # [1,2]
print(twoSum([3,3], 6)) # [0,1]