题目
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0
?请你找出所有满足条件且不重复的三元组。注意: 答案中不可以包含重复的三元组。
示例:
给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为: [ [-1, 0, 1], [-1, -1, 2] ] 注:返回的是两个集合,就是大集合中放两个小集合
思路
关键在于题目中说不可以包含重复的三元组,三元组是需要去重的,使用哈希表比较复杂
双指针法
比哈希法更高效
首先对数组排序,然后从i=0
开始遍历,定义两个指针left
和right
,left
指向i+1
的元素,right
指向最后一个元素,相当于a = nums[i],b = nums[left],c = nums[right]
,再在数组中找a+b+c=0
然后移动left
和right
指针,i
不动,移动两指针,因为数组已经排序好,如果nums[i] + nums[left] + nums[right] > 0
,说明right
应该向左移动,才能三数之和小一点;如果nums[i] + nums[left] + nums[right] < 0
,说明left
要右移才能让三数之和大一点,直到两指针相遇 ,则找到一个满足的元组,继续i++
下一轮判断
去重操作
-
对
a
的去重:if (i > 0 && nums[i] == nums[i - 1]) {//判断前一位和当前位是否相同 continue; }
因为如果是
nums[i] == nums[i +1]
情况下continue
的话,比如{-1,-1,2}
,前一个是-1
,后一个也是-1
,这样会直接pass
这个列表,而这是一个满足题意的列表。
所以才判断前一位是不是一样的元素,在{-1, -1 ,2}
中,当遍历到 第一个-1
的时候,只要前一位没有-1
,那么{-1, -1 ,2}
这组数据一样可以收录到结果集里 -
对
b,c
的去重
如果nums[right]
处和它的前一位相同,则right--
;如果nums[left]
和它的后一位相同,则left++
java代码
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++){
int right = nums.length - 1;
int left = i + 1;
if(nums[i] > 0){//如果排序后的数组第一个元素都大于0,则必不可能存在三数之和等于0
return result;
}
if(i > 0 && nums[i] == nums[i-1]){//对a进行去重
continue;
}
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]));//数组转成列表List
while(right > left && nums[right] == nums[right-1]) right--;
while(right > left && nums[left] == nums[left+1]) left++;
//找到答案时,双指针同时收缩,进行下一次循环
right--;
left++;
}
}
}
return result;
}
}