Problem:
Given an array of integers, find two numbers such that they add up to a specific target number.
The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2.
Please note that your returned answers (both index1 and index2) are not zero-based.
You may assume that each input would have exactly one solution.
Input: numbers={2, 7, 11, 15}, target=9
Output: index1=1, index2=2
Analysis:
The brute-force method is straightforward and its time complexity is O(n^2).
The second method is to use sorting. Since this quesiton requires the indices of two elements whose sum is equal to the target, we cannot sort the original array. An alternative way is to create a new array, each element of which is a pair of the value of element and it index. Sort this new array and use the linear search (O(n)). This method keeps the information of index of every element, the result is the collection of the second turples of two elements we found.
Note: Here, the binary search does not apply this case, since it needs to apply it every difference between the target value with an element (trasversal from the last element to the second one). The total time complexity is O(nlog n). This means that a binary search is better to use the case that search one given element but not a series of ones.
Note: The std::sort is not a stable sort. Then, we always need to sort the result.
The third method is to use Hash map. The time complexity of this method is O(n) and it needs an extra space complexity of O(n). The basic idea is as follows: Check the key target - nums[i] exists in the map. If yes, return the array of indices; if not, add nums[i] as a new key and i as the value.
There are two tricks here need to notice: (1) We should deal with the problem by two cases: target is odd or even: for the latter case, we need to check whether the size of the slot of target / 2 is bigger than or equal to 2; (2) If we only need to test such sum exists, we do not need to count the number of elements of each slot: we only need to test the number is not samller than 2. (This avoid the overflowwing of int.)
Code:
C++:
Solution 1 (Brute-force): This method cannot pass the large-data test.
1 vector<int> twoSum(vector<int>& nums, int target) { 2 vector<int> result; 3 if(nums.empty()) 4 return result; 5 6 for(int i = 0; i < nums.size(); ++i) { 7 for(int j = i; j < nums.size(); ++j) { 8 if(target == nums[i] + nums[j]) { 9 result.push_back(i); 10 result.push_back(j); 11 break; 12 } 13 } 14 } 15 16 return result; 17 }
Solution 2 (Sorting): (16 ms, not the fastest one: 8 or 12?)
1 static bool CompareFunction(pair<int, int>& left, pair<int, int>& right) 2 { 3 return left.first <= right.first; 4 } 5 6 vector<int> twoSum(vector<int>& nums, int target) { 7 vector<int> result; 8 if(nums.empty()) 9 return result; 10 11 vector<pair<int, int> > nums_index; 12 for(int i = 0; i < nums.size(); ++i) 13 nums_index.push_back(make_pair(nums[i], i)); 14 15 sort(nums_index.begin(), nums_index.end(), CompareFunction); 16 17 int start = 0; 18 int end = nums_index.size() - 1; 19 while(start < end) { 20 if(nums_index[start].first + nums_index[end].first == target) { 21 result.push_back(min(nums_index[start].second, nums_index[end].second) + 1); 22 result.push_back(max(nums_index[start].second, nums_index[end].second) + 1); 23 return result; 24 } else if(nums_index[start].first + nums_index[end].first < target) 25 for(++start; start < end && nums_index[start].first == nums_index[start - 1].first; ++start); 26 else 27 for(--end; start < end && nums_index[end].first == nums_index[end + 1].first; --end); 28 29 } 30 31 return result; 32 }
Solution 3 (Hash table):
1 vector<int> twoSum(vector<int> &nums, int target) { 2 map<int, int> h; 3 for(int i = 0; i < nums.size(); ++i) { 4 if(h.find(target - nums[i]) != h.end()) { 5 vector<int> result(1, h[target - nums[i]] + 1); 6 result.push_back(i + 1); 7 return result; 8 } 9 h[nums[i]] = i; 10 } 11 }