leetcode中的TWO SUM对结果进行了限制,You may assume that each input would have exactly one solution.
但是考虑实际情况,有可能在数列中,有多个组合的sum等于target。需要找到所有的情况。
1, 假设:在输入的数列中没有重复的数字,结果中数对不唯一
sort之后不跳出循环,接着寻找对应的数对。直到寻找完
vector<pair<int, int>> twoSum(vector<int>& nums, int target) {
vector<pair<int, int>> result;
vector<pair<int, int> > ipair;
size_t k = nums.size();
for (size_t i = 0; i < k; ++i)
{
ipair.push_back(make_pair(nums[i], i));
}
sort(ipair.begin(), ipair.end());
vector<pair<int, int>>::iterator pfound=ipair.begin(), pback = --ipair.end();
while (pfound < pback)
{
if (pfound->first + pback->first > target)
--pback;
else if (pfound->first + pback->first < target)
++pfound;
else
{
result.push_back(make_pair((pfound->second < pback->second ? pfound->second : pback->second) + 1),
(pfound->second > pback->second ? pfound->second : pback->second) + 1));
}
}
return result;
}
如果用unordered_map的话,代码如下:
vector<pair<int, int>> twoSum(vector<int> &numbers, int target) {
vector<pair<int, int>> result; //保存结果
int count = numbers.size();
int temp1;
unordered_map<int, int> numMap;
unordered_map<int, int>::const_iterator citer;
for(int j = 0; j < count; ++j)
{
temp1 = target - numbers[j];
citer = numMap.find(temp1);
if(citer != numMap.cend())
{
result.push_back(make_pair(citer->second + 1, j+1));
}
else
numMap[numbers[j]] = j;
}
return result;
}
2, 输入的数字有重复的情况,结果不唯 一
这个时候考虑的问题有点多,加入有个vector<int>,其中有100个元素均为1,求sum为2的数对,那么可以发现,此时答案有(1,2),(1,3)···(1,100),(2,3),(2,4),(2,100)···
这个时候任何算法,都要O(N^2)才能找完数对。但是实际情况我们能不能找到运算更快的算法,寻找结果(输入数字一般化,有重复但不都是相同的)?
答案是肯定的
烟客旅人 ( 烟客旅人 sigmainfy — tech-wonderland.net)有对这个问题的分析点击打开链接
但是这个分析有一定的局限性,就如above,所有元素有相同,而sum即为 self+self 的情况无法处理。
下面给出我的解法:
vector<pair<int, int>> twoSum(vector<int>& nums, int target) {
vector<pair<int, int>> result;
vector<pair<int, int> > ipair;
size_t k = nums.size();
for (size_t i = 0; i < k; ++i)
{
ipair.push_back(make_pair(nums[i], i));
}
sort(ipair.begin(), ipair.end());
vector<pair<int, int>>::iterator p1 = ipair.begin(), p2 = --ipair.end();
vector<pair<int, int>>::iterator oldp1 = p1;
while (p1 < p2)
{
if (p1->first + p2->first > target)
{
--p2;
}
else if (p1->first + p2->first < target)
{
++p1;
}
else
{
result.push_back(make_pair(min(p1->second, p2->second)+1, max(p1->second, p2->second)+1));
oldp1 = p1;
++p1;
while (p1->first + p2->first == target && p1 < p2)
{
result.push_back(make_pair(min(p1->second, p2->second)+1, max(p1->second, p2->second)+1));
++p1;
}
p1 = oldp1;
--p2;
}
}
return result;
}
举例子分析:
原始数据: vector<int> ivec{ 8,8, 5, 5, 5, 2, 3,3, 6, 9, 4, 1, 0, 7, 7, 7};
排序之后:0 1 2 3 3 4 5 5 5 6 7 7 7 8 8 9 (每个数字有对应的原始位置信息)
然后设置两个迭代器p1, p2分别指向 head 和 tail ,在 p1->first + p2->first 不相等的情况下,我们根据sum 和target 的对比,移动 p1 或 p2。
问题出现在相等的时候,如果相等那么我们假设有重复数字出现(如果不相等,重复数字不考虑,会step by step 跳过)
这时我们用oldp1来保存第一次相等的时候p1的位置,然后p1+1。然后进入相等循环测试看 p1 之后的数字和oldp1的数字是否相等,如果相等,把数对加入result,如果不等,那么说明重复数字结束,跳出循环。最后把p1回到oldp1位置,把后迭代器向前移一个(--p2),重新循环寻找数对之和等于target。
如此便可把所有合适的数对都找出来。
注意:位置都是从1开始的。1,2,3,····