力扣:15. 三数之和,哈希表解法详解

题目链接
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。

注意: 答案中不可以包含重复的三元组。

示例:

给定数组 nums = [-1, 0, 1, 2, -1, -4],

满足要求的三元组集合为: [ [-1, 0, 1], [-1, -1, 2] ]

本题有两种解法,一般推荐使用第一种双指针法,还有另一种比较麻烦的方法哈希表法,主要难点在于去重,本文主要解释第二种哈希表法,双指针法请见其他文章。

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-2; i++) {
            if(nums[i]>0){
                return res;
            }
            if(i>0&&nums[i]==nums[i-1]){
                continue;   //第一轮相同的已经全部找过了,再重复找也是子集
            }
            Set<Integer> set=new HashSet<>();   //保存c,放外面的话会保存非neg值(不是-b-c)导致错误
            for (int j = i+1; j < nums.length; j++) {
                if(j>i+2&&nums[j]==nums[j-1]&&nums[j-1]==nums[j-2]){
                    continue;   //可以允许一个是一样的因为c可能是前一个相同的,
                    // 但是第三个再相同就重复了,因为b已经在哈希表里了成功的话重复
                    // 不成功的话也没必要再判断一次
                }
                int neg=-nums[i]-nums[j];
                if(set.contains(neg)){
                    res.add(Arrays.asList(nums[i],nums[j],neg));
                    set.remove(neg);    //防止ab顺序不一样但是数字一样的情况
                }else{
                    set.add(nums[j]);
                }
            }
            
        }
        return res;
        
        //双指针法
        // List<List<Integer>> res=new ArrayList<>();
        // Arrays.sort(nums);
        // for (int i = 0; i < nums.length-2; i++) {
        //     //排序后如果第一个元素就大于0那么就不可能符合了
        //     if(nums[i]>0){
        //         return res;
        //     }
        //     //对a去重
        //     if(i>0&&nums[i]==nums[i-1]){
        //         continue;
        //     }
        //     int l=i+1;
        //     int r= nums.length-1;
        //     while(r>l){ //找三个元素所以不能重复用>
        //         int sum=nums[i]+nums[l]+nums[r];
        //         if(sum>0){
        //             r--;
        //         }else if(sum<0){
        //             l++;
        //         }else {
        //             res.add(Arrays.asList(nums[i],nums[l],nums[r]));
        //             while(r>l &&nums[r]==nums[r-1]){
        //                 r--;
        //             }
        //             while(r>l && nums[l]==nums[l+1]){
        //                 l++;
        //             }
        //             r--;
        //             l++;
        //         }
        //     }
        // }
        // return res;

    }
}

主要思想:利用哈希表记录下可能的c值,即为-a-b的值,每次固定遍历下a+b的值使用哈希表记录相应的c值,所以哈希表存在于第一个循环内,第二个循环外,可以在a值变换之后自动清空哈希表中的内容,防止下一轮的哈希表仍然存在上一轮的-a-b的值,和这一轮的c值相加并不等于0导致产生错误。

去重逻辑:a去重解释,第一轮a已经将所有可能的组合全部找过了,下一轮再重复找相等的a也是上一轮组合的子集导致重复,所以a重复直接跳过;b去重解释,可以允许b和之前重复一次,因为c可能是前一个相同的b值,这也是一种三元组可能,直接跳过可能会漏掉一种组合,但是第三个再相同不跳过就会重复了,因为上一轮b已经记录在哈希里了成功的话会查到重复组合,不成功的话也没必要再白白判断一次;c去重解释,防止a值和b值相等但是顺序不相等的可能,如果不去重产生a、b、c和b、a、c的话会导致结果重复,所以c用完之后就需要清除。

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值