描述
给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
例子
思路
可以参考二数之和的思路。
- 二数之和 字典 (不合适,因为同一个数可能被多个组合需要,二数之和只需要一个答案,所以没有此顾虑)
对于每个人,拉上第二个人去找第三个人,此时就变成2数之和了,如果,第二个人被需要,直接输出,如果第二个人不被需要,则填入字典(第一个第二个人都不被需要):d[0-第一个人-第二个人]=[第一个人,第二个人]
- 二数之和 双指针(需要先排序,好确定如何移动指针)推荐
先排序,遍历数组,对于每个数,取两个指针a,b,一个是它之后的数,一个是最后一个数,在a<b的情况下,如果和大于target,向前调b,如果和小于target,向后调a,如果,和为target,将此组合添加到结果
避免重复trick:
- 在外循环,如果现在的数和上一个数一样,就跳过,因为该数的选择比上一个数的选择更少,直接被囊括了
- 对于内循环,当找到一组答案后,如果nums[b]===nums[b-1],则跳过b-1,如果nums[a]==nums[a+1],则跳过a+1,因为nums[i]已经确定,该数跟上一个数一样的话,该组合也是重复的,故可略去
减少计算:
- 如果nums[i]+nums[i+1]+nums[i+2]>0 break #或nums[i]>0,则结束外循环。最小的数>0,则三数之和大于0,且后面的数都比nums[i]大,则后面的组合都有问题,
- 如果nums[i]+nums[n-1]+nums[n-2]<target continue #则最大的组合数都小于target直接下一个数
答案
- python
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
nums.sort()#方便去重
res = []
n=len(nums)
for i in range(n-2):
if i>0 and nums[i]==nums[i-1]:
continue
if nums[i]+nums[i+1]+nums[i+2] > 0:#或者nums[i]>0
break #最小的数>0,则三数之和大于0,且后面的数都比nums[i]大,则后面的组合都有问题,
if nums[i]+nums[n-1]+nums[n-2]<0: continue
a, b = i+1, n - 1
while a <b:
t = nums[a] + nums[i] + nums[b]
if t < 0:
a += 1
if t > 0:
b -= 1
if t == 0:
res.append([nums[i], nums[a], nums[b]])
while a<b and nums[b]==nums[b-1]:
b-=1
while a<b and nums[a]==nums[a+1]:
a+=1
a+=1
b-=1
return res
- c++
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
sort(nums.begin(), nums.end());
vector<vector<int>> v;
int n=nums.size();
for (int i=0; i<n-2; i++)
{
int a=i+1,b=nums.size()-1;
if (i>0 && nums[i]==nums[i-1]) continue;
if (nums[i]+nums[i+1]+nums[i+2]>0) break;//==nums[i]>0最小的数>0,则三数之和大于0,且后面的数都比nums[i]大,则后面的组合都有问题,
if (nums[i]+nums[n-1]+nums[n-2]<0) continue;
while (a<b)
{
int t = nums[i]+nums[a]+nums[b];
if (t<0) a++;
if (t>0) b--;
if (t==0)
{
vector<int> temp = {nums[i],nums[a],nums[b]};
v.push_back(temp);
while (a<b && nums[b]==nums[b-1]) b--;
while (a<b && nums[a]==nums[a+1]) a++;
a++;
b--;
}
}
}
return v;
}
};