给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
思路分析:
三数之和为0,即分以下三种情况:
1. 三个相等的数(0)
2. 两个相等的数+一个不相等的数
3. 三个不相等的数
需要考虑到的情况:
- 传入数组数组长度是否大于3
- 因为输出数组为有序的,是否排序后处理数组会更方便
- 三数之和要等于0,那么排序后的数组,当nums[0]>0,输出[]
- 输出的数组为不重复的三元组,就需要考虑其去重问题(重点)。
去重主要解决因两个或两个以上相等的值导致无效遍历的问题。
解法:
方法一:采用哈希表去重
//时间复杂度太高,超出时间限制
public List<List<Integer>> threeSum1(int[] nums) {
Arrays.sort(nums);
List<Integer> list;
Set<List<Integer>> set=new HashSet<List<Integer>>();
List<List<Integer>> lList=new ArrayList<List<Integer>>();
for(int i=0;i<nums.length-2;i++){
for(int j=i+1;j<nums.length-1;j++){
for(int k=j+1;k<nums.length;k++){
if(nums[i]+nums[j]+nums[k]==0){
list=new ArrayList<Integer>();
list.add(nums[i]);
list.add(nums[j]);
list.add(nums[k]);
set.add(list);
}
}
}
}
lList.addAll(set);
return lList;
}
方法二:采用双指针法
public List<List<Integer>> threeSum(int[] nums) {
List<Integer> list;
List<List<Integer>> lList=new ArrayList<List<Integer>>();
//如果数组长度小于3,直接返回空
if(nums.length<3){
return lList;
}
//对数组先进行排序
Arrays.sort(nums);
for(int i=0;i<nums.length;i++){
//如果第一个元素的值大于0,直接返回
if(nums[i]>0){
return lList;
}
if(i>0&&nums[i]==nums[i-1]){
continue;
}
int left=i+1;
int right=nums.length-1;
while(left<right){
if(nums[i]+nums[left]+nums[right]>0){
right--;
}else if(nums[i]+nums[left]+nums[right]<0){
left++;
}else{
list=new ArrayList<Integer>();
list.add(nums[i]);
list.add(nums[left]);
list.add(nums[right]);
lList.add(list);
//与26行,27行去重类似,该行如果放在添加进arrayList之前,可能会出现遗漏{0,0,0}的情况
//比如[0,0,0,0,0,1,2]
while(left<right&&nums[right]==nums[right-1]){
right--;
}
while(left<right&&nums[left]==nums[left+1]){
left++;
}
//得到答案后,i不变,通过双指针相向移动,保证三数之和可能为0
right--;
left++;
}
}
}
return lList;
}