题目描述
给你一个整数数组 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 。
思路
【来源:leetcode评论区】考虑先将整个数组从小到大重新排序sort()。然后for循环遍历每个位置(如果当前位置和前一个位置一样,那么出来的数组也会一样,需要判断并跳过),对剩余的从i+1到n-1的位置,设置left和right两个指针。
分别从i+1和n-1开始循环判断:
如果nums[i]+nums[left]+nums[right]<0说明整体需要增大,因此左指针left向右移动,
如果nums[i]+nums[left]+nums[right]>0说明整体需要减小,因此右指针right向左移动。
如果相等则找到目标数组,保存到结果中,同时考虑到数组不能重复,循环判断nums[left]是否与nums[left+1]是否相等,如果相等,则将left右移,对于right也是如此。循环判断结束后,当前left和right位置处的值应该分别和其下一个值不等。
此时再left++,right–,因此原本的nums[i]+nums[left]+nums[right]=0,所有left和right需要同时变化,同时外层循环退出条件需要注意left<right。
#include <vector>
#include <iostream>
#include <algorithm>
vector<vector<int>> solution(vector<int> nums)
{
int n = nums.size();
vector<vector<int> > ans;
sort(nums.begin(), nums.end());
for(int i = 0; i<n; i++)
{
if(i>0 && nums[i]==nums[i-1]) continue;
int left = i+1,right = n-1;
while(left<right)
{
if(nums[i]+nums[left]+nums[right]<0)
left++;
else if(nums[i]+nums[left]+nums[right]>0)
right--;
else
{
ans.push_back({nums[i], nums[left], nums[right]}); // 这个用不了emplace_back()不知道为什么
while(left+1<n && nums[left]==nums[left+1])
left++;
while(right-1>0 && nums[right]==nums[right-1])
right--;
left++;
right--;
}
}
}
return ans;
}