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:
There are three typical methods for solving this problem. The first method is brute-force. This method is to use a two-level nested-loops to search the solution. The second one is to use a hash-table to store entry value and the index of the elements which are equal to this value. The third method is to build a new array, whose entry is a struct constituted of the value of an element and its index. Sort this new array based on the entry value and find the solution from two ends of the new array (This search is not a binary-search and its time-complexity is O(n) but not the O(log n)).
Sample code:
Method 1:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> indices;
if(nums.empty())
return indices;
for(int i = 0; i < nums.size(); ++i) {
for(int j = i + 1; j < nums.size(); ++j) {
if(nums[i] + nums[j] == target) {
indices.push_back(i + 1);
indices.push_back(j + 1);
return indices;
}
}
}
}
Method 2:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> indices;
if(nums.empty())
return indices;
map<int, vector<int> > value_map_index;
vector<int> keys;
for(int i = 0; i < nums.size(); ++i) {
if(value_map_index.find(nums[i]) == value_map_index.end()) {
vector<int> indices;
indices.push_back(i);
value_map_index[nums[i]] = indices;
keys.push_back(nums[i]);
} else
value_map_index[nums[i]].push_back(i);
}
if(target % 2 == 0) {
if(value_map_index[target / 2].size() > 1) {
indices.push_back(value_map_index[target / 2][0] + 1);
indices.push_back(value_map_index[target / 2][1] + 1);
return indices;
}
}
sort(keys.begin(), keys.end());
int start = 0;
int end = keys.size() - 1;
while(start < end) {
if(start == end - 1 || keys[start] + keys[end] == target) {
indices.push_back(value_map_index[keys[start]][0] < value_map_index[keys[end]][0] ?
value_map_index[keys[start]][0] + 1 : value_map_index[keys[end]][0] + 1);
indices.push_back(value_map_index[keys[start]][0] > value_map_index[keys[end]][0] ?
value_map_index[keys[start]][0] + 1 : value_map_index[keys[end]][0] + 1);
break;
}
if(keys[start] + keys[end] < target)
++start;
else
--end;
}
return indices;
}
Method 3:
struct ValueIndex
{
ValueIndex(int val, int index) :
value(val), index(index) {}
int value;
int index;
};
static bool CompareFunctionEq(const ValueIndex& lhs, const ValueIndex& rhs)
{
return lhs.value <= rhs.value;
}
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> indices;
if(nums.empty())
return indices;
vector<ValueIndex> new_array;
for(int i = 0; i < nums.size(); ++i) {
new_array.push_back(ValueIndex(nums[i], i));
}
sort(new_array.begin(), new_array.end(), CompareFunctionEq);
int start = 0;
int end = new_array.size() - 1;
while(start < end) {
if(new_array[start].value + new_array[end].value == target) {
indices.push_back(new_array[start].index < new_array[end].index ?
new_array[start].index + 1 : new_array[end].index + 1);
indices.push_back(new_array[start].index > new_array[end].index ?
new_array[start].index + 1 : new_array[end].index + 1);
break;
} else if(new_array[start].value + new_array[end].value < target)
++start;
else
--end;
}
return indices;
}