给定一个包含 n 个整数的数组
nums
,判断nums
中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。注意:答案中不可以包含重复的三元组。
思路:根据两数之和,三数之和为具有多个target的两数之和,可以使用hash表或者对撞指针,方法比较明确,但三数之和难点在于结果去重。
使用hash表去重思路一直存在bug,因此先使用对撞指针。
对撞指针思路:
1、首先将数组排序,从小到大。
2、避免结果重复,只将负数和0作为target。
3、从数组首位开始,依次将当前数的相反数作为target,并指定其后数组左右两端作为左右指针。
4、时刻确保左指针小于右指针,判断左指针与右指针数加和是否等于target,若小于target,则说明左指针比较小,将左指针右移,若大于target,则说明右指针过大,将右指针左移。
5、若等于target,则找到目标,将三个数排好序添加到结果集中,然后循环判断左指针下一位是否与当前数相同,相同则左指针右移,然后循环判断右指针下一位是否与当前数相同,相同则左移,过滤掉相同的数,然后再左指针右移一位,右指针左移一位。
6、target一轮循环结束,需要循环判断下一位数是否与当前target相同,若相同则循环将相同的target过滤掉。
public List<List<Integer>> threeSum(int[] nums) {
//对撞指针
int left;
int right;
int target;
List<Integer> list = new ArrayList<>();
List<List<Integer>> res = new ArrayList<>();
if(nums.length<3){return res;}
Arrays.sort(nums);
for(int i=0;i<nums.length-1&&nums[i]<=0;i++){
left = i+1;
right = nums.length-1;
target = -nums[i];
while(left<right){
if(left<right&&nums[left]+nums[right]==target){
list = new ArrayList<>();
list.add(nums[left]);
list.add(nums[right]);
list.add(-target);
Collections.sort(list);
res.add(list);
while(left<right&&nums[left]==nums[left+1]){left++;}
while(left<right&&nums[right]==nums[right-1]){right--;}
left++;
right--;
}else if(left<right&&nums[left]+nums[right]<target){
left++;
}else if(left<right){
right--;
}
}
while(i<nums.length-1&&nums[i]==nums[i+1]){i++;}
}
return res;
}