三数之和--如何让三只指针帮你去重?

欢迎关注我的刷题专栏 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;
    }
}

然后我们可以做一道 在此基础上的变式题: 最接近的三数之和

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值