作为两数之和的扩展,我们自然需要先看一看两数之和是怎么做的
两数和是求两个数他们的下标使得和达到target, 简便做法是设计一个map,在遍历之前寻找map里面存在target - nums[i] 的数据,从而避免一个数被重复计算
三数和的最大不同是 他要求返回所以的不重复的三元组,这就使得我们不可能简单的套用两数和的方式来把外层循环当作target计算,因为这样在返回一个结果的时候是保证正确的,但是之后可能map里面存在错误
所以三数和我们需要采用 排序 + 双指针 的方法
因为不重复的本质就是 在给定 a<=b<=c的情况下,只能有这样形式的一组数据 -> 排序
双指针是一个从前往后 一个从后往前 相遇时终止 这是因为 a+b+c =0 b在增大的过程中 c必须减小
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
//这个题目和两数之和很不一样,因为他要的是返回所以不重复的三元组
//两数之和要求的是的三元组
vector<vector<int>> ans;
//根据不重复的三元组入手
sort(nums.begin(),nums.end());
for(int first=0;first<nums.size();first++){
if(first>0 && nums[first]==nums[first-1]){
continue;
}//需要和上一次枚举的数不一样
int target=(-1)*nums[first];
int third=nums.size()-1; //c从最后取
for(int second=first+1;second<nums.size();second++){
if(second>first+1 && nums[second] == nums[second-1]){
//为什么这里要有一个second>first+1呢
//防止first和second临近的这个答案被 continue掉 例如-1 -1 2
continue;
}
while(second<third && nums[second] + nums[third] > target){
third--;
}
if(second == third){
break;
}
if(nums[first]+nums[second]+nums[third] == 0){
ans.push_back( {nums[first],nums[second],nums[third]} );
}
}
}
return ans;
}
};
代码里面有两个小tips:
1.对于 a(或者b或者c) 的更新,必须是严格大于上一次的数据 ,不能和上一次相等
2.a和b可以相等, 也就是second > first + 1 的时候才去检验 nums[second] == nums[second-1] ?