您的位置:首页 > 其它

Leetcode-15: 3Sum

2018-03-13 14:01 267 查看
这题其实不容易调通,难就难在对重复元素的排除上。比如说a[]={-2,0,0,2,2},只能输出一个[-2,0,2],但对于a[]={-4,-1,-1,0,1,2,3},必须要输出2个: [-1,-1,2]和[-1,0,1],而对于a[]={0,0,0,0},又只能输出一个[0,0,0]。
注意:
1) 此题不存在O(nlogn)的解法。我一开始设想了一个解法是用两个指针p1,p2,一前一后。假设两个指针对应数和为sum,中间那个数用binary search找-sum。如果找不到,并且sum>0,就p2--,否则p1++。
比如说,a[]={-7,-4,0,1,1,3},-7+3=-4找4找不到,p1++,-4+3=-1,找到了。
但这种方法是不对的。举个反例,a[]={-7,-4,-4,0,1,1,2,8},-7+8=1,此时要p2--,但p2不能动,因为-4-4+8=0。这个binary search的方法不对的原因我认为是:如果找不到解,不能确定p1和p2怎么动,有可能只p1++,也可能只p2--,也可能p1++和p2--都要进行,所以这种试图两边往中间移动的思路不对。
2) 正解的方法是只锁定一边,也就是i++,然后从i+1到nums.size()-1里面用p1,p2,先算sum2=nums[p1]+nums[p2],然后sum2和-nums[i]比较,若sum2>-nums[i],则p2--; 若sum2<-nums[i],则p1++;如果两者相等,说明找到一个解。要注意此时应该再加一个while循环,把所有的解都弄出来。
这两行非常重要,里面又是两个小循环:
while ((++p1<p2) && (nums[p1]==nums[p1-1]));
while ((p1<--p2) && (nums[p2]==nums[p2+1]));它们表示将p1,p2移到不重复的地方,假设nums[1]=-1, p1~p2对应[-1,-1,0,1,2],此时找到一个解[-1,-1,2]。第一个while会将数组变成[-1,0,1,2],第二个while会将数组变成[-1,0,1],然后while(p1<p2)循环又会发现另一个解[-1,0,1]。注意这两个解都是i=1时发现的。
但如果input数组是[-2,0,0,2,2,2,2]时,一开始while(p1<p2)的循环内会发现[-2,0,2]这个解,过完上面两个循环数组会变成[0,0,2],所以不会有重复解出现。
我一开始将上面两个循环写成 while ((p1<p2) && (nums[p1]==nums[p1-1])) p1++;
while ((p1<p2) && (nums[p2]==nums[p2+1])) p2--;这是不对的,因为第2个循环的(nums[p2]==nums[p2+1])不满足,所以p2不会--。也就是说,此时应该先无条件p1++,p2--,然后再看p1和p2的相邻元素是否一致。
3) 最开始的 if ((i==0)||(nums[i]!=nums[i-1]))也可以防止重复解出现。如果nums[i-1]和nums[i]都是解的一部分也没关系,上次i-1的时候就已经输出了(因为已经i++),这是可以直接跳过nums[i]。
4) 此题避免重复解也可以用set或map。#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

vector<vector<int> > threeSum(vector<int>& nums) {
int i=0, p1=0, p2=0;
vector<vector<int> > sol;

if (nums.size()==0) return sol;

sort(nums.begin(), nums.end());

while(i<nums.size()-1) {

if ((i==0)||(nums[i]!=nums[i-1])) {
p1=i+1; p2=nums.size()-1;
while(p1<p2) { //target is -nums[i]
int sum2=nums[p1]+nums[p2];
if (sum2>-nums[i])
p2--;
else if (sum2<-nums[i])
p1++;
else {
//find one solution
vector<int> tmpV;
tmpV.push_back(nums[p1]); tmpV.push_back(nums[p2]); tmpV.push_back(nums[i]);
sol.push_back(tmpV);
cout<<" ["<<nums[p1]<<", "<<nums[p2]<<", "<<-sum2<<"]"<<endl;
while ((++p1<p2) && (nums[p1]==nums[p1-1])); //Attention, ++p1
while ((p1<--p2) && (nums[p2]==nums[p2+1])); //Attention, --p2
}
}
}
i++;
}

return sol;
}

int main()
{

vector<int> S1={-1, 0, 1, 2, -1, -4};
threeSum(S1);
cout<
4000
;<endl;

vector<int> S2={0,0,0,0};
threeSum(S2);
cout<<endl;

vector<int> S3={-2,0,1,1,2};
threeSum(S3);
cout<<endl;

vector<int> S4={-2,0,0,2,2};
threeSum(S4);
cout<<endl;

vector<int> S5={-2,0,1,1,1,2};
threeSum(S5);
cout<<endl;

vector<int> S6={-3,1,2,2,2,2};
threeSum(S6);
cout<<endl;

vector<int> S7;
threeSum(S7);
cout<<endl;

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Leetcode