欢迎关注我的刷题专栏 zhangyixing1007/leetcode
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例:
给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为: [ [-1, 0, 1], [-1, -1, 2] ]
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/3sum 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
原题戳这里
划重点:答案中不可以包含重复的三元组。
我们来理解一下这句话。
Q1:nums=[-1,-1,2], ans=[[-1,-1,2]]是重复的三元组嘛?
A1:显然不是,这里只有一组三元组,虽然这组三元组中有两个-1,但,这也不叫重复。
Q2:nums=[-1,-1,-1,2], ans=?
A2:ans=[[-1,-1,2]],这里ans中的-1无论是取的第0/1/2个都没有关系。
Q1告诉我们想要避免重复值,显然不是不允许三元组中存在重复的元素。这意味着,我们不能简单粗暴直接对数组去重。
Q2告诉我们无论相同的元素有多少个,它们的三元组表示都不能重复–看起来可以用set直接对三元组去重?
是的,但还可以更加简单。
以下为代码,我会详细注释,它是如何完成答案中不可以包含重复的三元组这个目标的。
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
if(nums==null||nums.length<3)
return new ArrayList<>();
List<List<Integer>> list=new ArrayList<>();
Arrays.sort(nums);//求数之和的惯常操作就是排序
//以下基本思路:
//i是最"左”端固定的指针,l=i+1, r=nums.length-1
//检查 nums[i]+nums[l]+nums[r] 的正负零
//若为正,说明整体位置偏右,r--
//若为负,说明整体位置偏左,l++
for(int i=0; i<nums.length-2; i++){
int l=i+1, r=nums.length-1;
while(i+1<nums.length&&nums[i]==nums[i+1]) i++;
//以上两行不能换序
//否则就彻底排除了
//nums[i]==nums[l]的情况,这是不合理的
while(l<r){
if(nums[i]+nums[l]+nums[r]>0) {
while(l<r-1&&nums[r]==nums[r-1]) r--;
r--;
}else if (nums[i]+nums[l]+nums[r]<0) {
while(l+1<r&&nums[l]==nums[l+1]) l++;
l++;
}else{
List<Integer> L=new ArrayList<>();
L.add(nums[i]);
L.add(nums[l]);
L.add(nums[r]);
list.add(L);
while(l+1<r&&nums[l]==nums[l+1]) l++;//[1]
while(l<r-1&&nums[r]==nums[r-1]) r--;//[2]
//[1][2]这里是对nums[l],nums[r]进行去重
//避免再次得到和[nums[i], nums[l], nums[r]]一样的三元组
//但经历过[1]之后,l指向的是最后一个与l自增之前相同的值
//所以接下来这一行代码是必不可少的
l++; r--;
}
}
}
return list;
}
}
然后我们可以做一道 在此基础上的变式题: 最接近的三数之和。