给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4], 满足要求的三元组集合为: [ [-1, 0, 1], [-1, -1, 2] ]
解法一:
穷举,时间复杂度为O(n3),会超时
解法二:
题目是求a+b+c=0,那么如果你用
for()
for()
for(){
a+b+c==0;
}
这是一个三数求和问题,
但是b+c=-a
因此,这就间接转化成了一个两数求和的问题。
因为要处理重复问题,因此将数组先排序,排序过后,取a = nums[i],则接下来在i+1 - len-1的范围寻找b和c使b和c满足b+c = -a;
假设nums = [-1, 0, 1, 2, -1, -4],
排序后nums=[-4,-1,-1,0,1,2];
当a = nums[i]时,则nums[len-1]为接下来最大的数,nums[i+1]为大于等于a的数。
如果nums[len-1] + nums[i+1]大于了a,那么b和c则只能出现在i+1 - <(len-1)的范围。
这和二分查找的思路很像,我们可以另a = nums[i] ,b = nums[i+1] ,c = nums[len-1]。
如果b+c>-a ,那么c往前移动
如果b+c<-a,那么a往后移动。
因为数组中有重复的数字,所以移动的时候要判断是否和移动前的数重复,如果重复,则应该继续移动。
对于nums=[-4,-1,-1,0,1,2];,当a = nums[1] = -1的时候,可以找到解{-1,0,1}。
当a = nums[2] = -1的时候,又可以找到解{-1,0,1}
这两个解重复了,与题目要求不符,那么排查重复的原因。
原因很显然是因为对于重复的a,那么如果有解,则必然会找到重复的解。
因此在i>=1的时候,判断nums[i] 是否和nums[i-1]相等,如果相等则跳过。
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> ans = new LinkedList<List<Integer>>();
if(nums.length <= 2){
return ans;
}
Arrays.sort(nums);
int len = nums.length;
for(int i=0;i<len-2;i++){
if(i==0 || (i>0 && nums[i]!=nums[i-1])){//去除重复的解
int l = i+1,r=len-1,sum=0-nums[i];
while(l<r){
if(nums[l]+nums[r]==sum){
ans.add(Arrays.asList(nums[i],nums[l],nums[r]));//找到一组解
while(l<r && nums[l] == nums[l+1]) l++;判断相等是为了 去除重复解 和减少不必要的查询情况
while(l<r && nums[r] == nums[r-1]) r--;
l++;
r--;
}else if(nums[l]+nums[r] <sum){
while(l<r && nums[l] == nums[l+1]) l++;
l++;
}else{
while(l<r && nums[r] == nums[r-1]) r--;
r--;
}
}
}
}
return ans;
}
}
相关: