leetcode--TWO SUM延伸(假设答案不唯一、假设输入有相同数字)

来源:互联网 发布:中国历年实际gdp数据 编辑:程序博客网 时间:2024/06/05 22:57

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));}elsenumMap[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,····


0 0