给你一个整数数组 nums
,判断是否存在三元组 [nums[i], nums[j], nums[k]]
满足 i != j
、i != k
且 j != k
,同时还满足 nums[i] + nums[j] + nums[k] == 0
。请你返回所有和为 0
且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4] 输出:[[-1,-1,2],[-1,0,1]] 解释: nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。 nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。 nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。 不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。 注意,输出的顺序和三元组的顺序并不重要。
示例 2:
输入:nums = [0,1,1] 输出:[] 解释:唯一可能的三元组和不为 0 。
示例 3:
输入:nums = [0,0,0] 输出:[[0,0,0]] 解释:唯一可能的三元组和为 0 。
1.先将 nums 从小到大 排序,
2.固定 3 个指针中最左(最小)元素的指针 frist,双指针 second,third分设在数组索引 (frist,nums.size()) 两端。
3.双指针 second , third 交替向中间移动,记录对于每个固定指针 frist 的所有满足 nums[frist] + nums[second] + nums[third] == 0 的组合:
当 nums[frist] > 0 时直接break跳出:因为 nums[third] >= nums[second] >= nums[frist] > 0,即 3 个元素都大于 0 ,在此固定指针 frist 之后不可能再找到结果了。
4.记录sum = nums[frist] + nums[second] + nums[third],并按照以下规则执行双指针移动:
当sum < 0时,frist ++;
当sum > 0时,third --;
当s == 0时,记录组合[frist, second , third]至ans,执行frist ++和third --并跳过所有重复的nums[second]和nums[third],防止记录到重复组合。
优化:1.因为排好序,当(nums[frist]+nums[frist+1]+nums[frist+2])>0,则不会再有三个数相加为0.
2.同理,当(nums[frist]+nums[n-1]+nums[n-2])<0,则当前 frist 不会有满足三数之和为0的.
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums)
{
sort(nums.begin(),nums.end());
vector<vector<int>>ans;
int n=nums.size();
for(int frist=0;frist<n-2;frist++)//因为优化一所以frist<n-2
{
int x=nums[frist];
if(x>0)
break;
if(frist&&x==nums[frist-1])//跳过重复数字
{
continue;
}
if((nums[frist]+nums[frist+1]+nums[frist+2])>0)//优化一
break;
if((nums[frist]+nums[n-1]+nums[n-2])<0)//优化二
continue;
int second=frist+1,third=n-1;
while(second<third)
{
int sum=x+nums[second]+nums[third];
if(sum<0)
{
++second;
}
else if(sum>0)
{
--third;
}
else
{
ans.push_back({x, nums[second], nums[third]});
second++;
while(second<third&&nums[second]==nums[second-1])//跳过重复数字
{
second++;
}
third--;
while(second<third&&nums[third]==nums[third+1])//跳过重复数字
{
third--;
}
}
}
}
return ans;
}
};