57 三数之和
原题网址:https://www.lintcode.com/problem/3sum/description
描述
给出一个有n个整数的数组S,在S中找到三个整数a, b, c,找到所有使得a + b + c = 0的三元组。
在三元组(a, b, c),要求a <= b <= c。
结果不能包含重复的三元组。
您在真实的面试中是否遇到过这个题?
样例
如S = {-1 0 1 2 -1 -4}, 你需要返回的三元组集合的是:
(-1, 0, 1)
(-1, -1, 2)
标签
排序
两根指针
数组
思路:
不考虑时间复杂度、空间复杂度的话,三重循环暴力破解,唉,菜鸟第一想法。找到一组答案后判断下是否与result中已有组合重复,这个判重可以单独定义成一个函数。
AC代码:
class Solution {
public:
/**
* @param numbers: Give an array numbers of n integer
* @return: Find all unique triplets in the array which gives the sum of zero.
*/
vector<vector<int>> threeSum(vector<int> &numbers) {
// write your code here
vector<vector<int>> result;
int size=numbers.size();
for (int i=0;i<size;i++)
{
for (int j=i+1;j<size;j++)
{
for (int k=j+1;k<size;k++)
{
if (numbers[i]+numbers[j]+numbers[k]==0)
{
vector<int> temp;
temp.push_back(numbers[i]);
temp.push_back(numbers[j]);
temp.push_back(numbers[k]);
sort(temp.begin(),temp.end());
if (result.empty())
{
result.push_back(temp);
}
else
{
bool canInsert=true;
for (int ind=0;ind<(int)result.size();ind++)
{
if(same(temp,result[ind]))
{
canInsert=false;
break;
}
}
if (canInsert)
{
result.push_back(temp);
}
}
}
}
}
}
return result;
}
bool same(vector<int> num1,vector<int> num2)
{
for (int i=0;i<(int)num1.size();i++)
{
if (num1[i]!=num2[i])
{
return false;
}
}
return true;
}
};
优化算法: 参考 http://www.cnblogs.com/grandyang/p/4481576.html 与 https://www.cnblogs.com/eudiwffe/p/6282635.html
最开始我也是顺着两数之和的思路,先固定一个索引,另外两个数用哈希表,但会造成重复问题,并且会漏检一些组合,比如有多种组合nums【j】+ nums【k】= target的情况,只能检测出一种。
网上看了别人的答案后醍醐灌顶,膜拜大神。
详细见上面链接,简单说来就是先排序,然后固定一个数i,再用两个指针一根从头(i+1)一根从尾(n-1)遍历余下的元素,如果三个数的和等于0,push到结果中。如果和大于0,尾指针前移(减小总体和)。反之如果和小于0,头指针后移(增大总体和)。
这里尤其注意去除重复,因为数组已经排过序,只需要判断i,j,k三根指针是否与上一个指向元素相同就可以了。
代码,Lintcode说我 Time Limit Exceeded,emmmm……暴力破解反而通过?费解
class Solution {
public:
/**
* @param numbers: Give an array numbers of n integer
* @return: Find all unique triplets in the array which gives the sum of zero.
*/
vector<vector<int>> threeSum(vector<int> &numbers) {
// write your code here
vector<vector<int>> result;
int n=numbers.size();
sort(numbers.begin(),numbers.end());
for (int i=0;i<n;i++)
{
if (numbers[i]>0)
{
break;
}
if (i>0&&numbers[i]==numbers[i-1])//去除重复;
{
continue;
}
int j=i+1,k=n-1;
while(j<k)
{
if (j>i+1&&numbers[j-1]==numbers[j])//去除重复;
{
continue;
}
if (k<n-1&&numbers[k]==numbers[k+1])//去除重复;
{
continue;
}
if (numbers[i]+numbers[j]+numbers[k]==0)
{
vector<int> tmp(3,numbers[i]);
tmp[1]=numbers[j];
tmp[2]=numbers[k];
result.push_back(tmp);
j++;
k--;
}
else if (numbers[i]+numbers[j]+numbers[k]>0)
{
k--;
}
else
{
j++;
}
}
}
return result;
}
};