给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
第一个思路,想到了遍历出所有的三元组,找到符合条件的解即可。
由于不能出现重复的三元组,所以三轮每次循环的值不能重复。
想到回溯,因为可以剪枝嘛!不过好像和优化的三重for循环没有什么区别!!!
//回溯法
class Solution {
List<List<Integer>> res=new ArrayList<>();
public List<List<Integer>> threeSum(int[] nums) {
//对数组进行排序
Arrays.sort(nums);
List<Integer> temp=new ArrayList<>();
dfs(nums,nums.length,-1,0,temp);
return res;
}
private void dfs(int[] nums, int length, int j, int sum,List<Integer> temp) {
if(sum==0&&temp.size()==3){
res.add(new ArrayList(temp));
return;
}else if(temp.size()>3){
return;
}
for(int i=j+1;i<length;i++){
if(i==j+1){
temp.add(nums[i]);
sum=sum+nums[i];
dfs(nums,nums.length,i,sum,temp);
temp.remove(temp.size()-1);
sum=sum-nums[i];
}
else if(nums[i]!=nums[i-1]){
temp.add(nums[i]);
sum=sum+nums[i];
dfs(nums,nums.length,i,sum,temp);
temp.remove(temp.size()-1);
sum=sum-nums[i];
}
}
}
}
时间复杂度最坏为O(n的3次方)
看题解继续改良:
如果我们固定了前两重循环枚举到的元素a,b,那么最后一重循环c是唯一解。那我们向后移动b时,由于数组是排好序的,所以c只可能在上一个c的前面。
这样一个增大,另一个减小的情况,我们可以用双指针来解决,一个指b,一个指c
//双指针
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
int left;
int right;
List<List<Integer>> res = new ArrayList<>();
for (int i = 0; i < nums.length - 1; i++) {
if (i == 0 || nums[i] != nums[i - 1]) {
left = i + 1;
right = nums.length - 1;
while (left != right) {
if(left>i+1&&nums[left]==nums[left-1]){
left++;
continue;
}
if(right<nums.length-1&&nums[right]==nums[right+1]){
right--;
continue;
}
if(nums[i]+nums[left]+nums[right]==0){
List<Integer> list=new ArrayList<>();
list.add(nums[i]);
list.add(nums[left]);
list.add(nums[right]);
res.add(list);
left++;
}else if(nums[i]+nums[left]+nums[right]>0){
right--;
}else {
left++;
}
}
}
}
return res;
}
}
时间复杂度为O(n的平方)