题目:
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
实例:
给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
题解:
首先想到的思路是暴力法,但是三个元素遍历的话时间复杂度为O(n^3),很容易超时,所以我们可以想到把其中一个元素固定,然后用双指针法查找剩下数组元素中的两个符合条件的值,这样的话时间复杂度为O(n ^2)。
要用双指针法我们首先需要将数组排好序,磨刀不误砍柴工。然后遍历数组,我们遍历所找到的的元素 i 其实是是三元素中最小的元素,然后在[i+1,n-1]内用双指针寻找剩下两个元素,在真正的用双指针法之前,我们在判断num[i]时可以利用性质适当的舍去不可能存在解的情况:①如果num[i]>0,在最小元素都大于0的情况下我们不可能找到解;②如果存在重复元素,我们只考虑该元素首次出现时的情况,避免重复解;
然后令左指针 L=i+1,右指针 R=n−1,当 L<R 时,执行循环:
当nums[i]+nums[L]+nums[R]==0,执行循环,判断左界和右界是否和下一位置重复,去除重复解。并同时将 L,RL,R 移到下一位置,寻找新的解
若和大于 0,说明 nums[R] 太大,R左移;若和小于 0,说明 nums[L]太小,L右移。
代码如下:
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> lists=new ArrayList<>();
int len=nums.length;
if(nums==null||len<3) return lists;
Arrays.sort(nums);
for(int i=0;i<len-2;i++){
if(nums[i]>0) return lists;
if(i>0){
if(nums[i-1]==nums[i]) continue;
}
int now=nums[i];
int left=i+1,right=len-1;
while(right>left){
int le=nums[left],ri=nums[right];
int sum=le+ri+now;
if(sum==0){
List list=new ArrayList();
list.add(now);
list.add(le);
list.add(ri);
lists.add(list);
while(left<right && nums[left+1]==le) left++;
while(left<right && nums[right-1]==ri) right--;
right--;
left++;
}
else if(sum>0) right--;
else left++;
}
}
return lists;
}
}