给你一个整数数组 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 。
这道题目使用双指针法 要比哈希法高效一些
首先将数组排序,然后有一层for循环,i从下标0的地方开始,同时定一个下标left在i+1的位置上,将下标right定义在结尾的位置上。
还是在数组中找到a+b+c=0,即nums[i]+nums[left]+nums[right]=0
接下来移动left和right:
-
如果nums[i]+nums[left]+nums[right]>0说明和大了 因为数组是排序过的,所以right应该向左移动
-
如果nums[i]+nums[left]+nums[right]<0说明和小了 left应该向右移动,知道left和right相遇位置
去重逻辑:
主要考虑三个数的去重。 a, b ,c, 对应的就是 nums[i],nums[left],nums[right]
a的去重:
a 如果重复了怎么办,a是nums里遍历的元素,那么应该直接跳过去。
但这里有一个问题,是判断 nums[i] 与 nums[i + 1]是否相同,还是判断 nums[i] 与 nums[i-1] 是否相同。
如果我们的写法是 这样:
if (nums[i] == nums[i + 1]) { // 去重操作
continue;
}
那就我们就把 三元组中出现重复元素的情况直接pass掉了。 例如{-1, -1 ,2} 这组数据,当遍历到第一个-1 的时候,判断 下一个也是-1,那这组数据就pass了。
我们要做的是 不能有重复的三元组,但三元组内的元素是可以重复的!
所以这里是有两个重复的维度。
那么应该这么写:
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
这么写就是当前使用 nums[i],我们判断前一位是不是一样的元素,在看 {-1, -1 ,2} 这组数据,当遍历到 第一个 -1 的时候,只要前一位没有-1,那么 {-1, -1 ,2} 这组数据一样可以收录到 结果集里。
b与c的去重: 对b和c的去重应该放在找到一个三元组之后,并且要收缩双指针
while(right>left){
int sum=nums[i]+nums[left]+nums[right];
if(sum>0){
right--;
} else if(sum<0){
left++;
} else{
result.add(Arrays.asList(nums[i],nums[left],nums[right]));
while(right>left&&nums[left]==nums[left+1]) left++;
while(right>left&&nums[right]==nums[right-1]) right--;
right--;
left++;
}
}
代码:
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> result=new ArrayList<>();
Arrays.sort(nums);
for(int i=0;i<nums.length;i++){
if(nums[i]>0){
return result;
}
if(i>0&&nums[i]==nums[i-1]){
continue;
}
int left=i+1;
int right=nums.length-1;
while(right>left){
int sum=nums[i]+nums[left]+nums[right];
if(sum>0){
right--;
} else if(sum<0){
left++;
} else{
result.add(Arrays.asList(nums[i],nums[left],nums[right]));
while(right>left&&nums[left]==nums[left+1]) left++;
while(right>left&&nums[right]==nums[right-1]) right--;
right--;
left++;
}
}
}
return result;
}
}