给你一个整数数组 nums
,判断是否存在三元组 [nums[i], nums[j], nums[k]]
满足 i != j
、i != k
且 j != k
,同时还满足 nums[i] + nums[j] + nums[k] == 0
。请
你返回所有和为 0
且不重复的三元组。
**注意:**答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。
题解
如果是不去重的情况,可以用哈希表解决:先遍历两遍个数组,将两个数组的和作为key,和出现的次数作为value,然后再遍历一遍数组看需要的值是否在map里面出现。
当要考虑去重的情况时,先给数组排序,然后用双指针的方法:先固定 i,然后left=i+1,right=nums.length-1,左边和右边不断移动,求出此时三数的和,如果大了,right–,小了则right ++,直到三数之和为0,此时将三个数放到列表里面。
注意
-
怎么给i 去重
如果当前这个数和前一个数相等,说明这个数已经使用过了,continue跳过。必须是i和i-1相比,因为left=i+1;
-
怎么给left 和right 去重
当和已经为0 时,如果 nums[right] 和nums[right-1]相等,此时跳过,left同理。
-
while 循环条件 left 为什么不能等于 right
因为题目要求的是三数之和,如果left==right ,那此时两个指针指向同一个数,就变成两数之和了。
-
asList的使用方法
将对象型(Integer)数组值转化为列表
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> res=new ArrayList<>();
Arrays.sort(nums);
for(int i=0;i<nums.length;i++){
//排序之后的值大于0 ,之后的和相加都只能大于0
if(nums[i]>0) return res;
//对a去重 **注意**
if(i>0 && nums[i]==nums[i-1]){
continue;
}
int left=i+1;
int right=nums.length-1;
//left 不能等于right **
while(left<right){
int sum=nums[i]+nums[left]+nums[right];
if(sum>0){
right--;
}else if(sum<0){
left++;
}else{
res.add(Arrays.asList(nums[i],nums[left],nums[right]));
while(right>left && nums[right]==nums[right-1]) right--; //right去
while(right>left && nums[left]==nums[left+1]) left++; //left去重
right--;
left++;
}
}
}
return res;
}
}