三数之和

目录

一:题目链接

二:题目思路:

三:代码实现


一:题目链接

        题目理解比较简单,需要注意的是最后返回的三元组比如 [-1,0,1] 和 [ 0 , 1 ,-1] 是同一种,应当返回这两其中一个就行。

二:题目思路:

        这道题可以利用上我们前面所讲的利用 数组的单调性 + 双指针 的算法思想来解决这问题。

        如图,首先,先给数组排个序,让数组呈现单调性,定义起始 i 下标作为固定的数字,我们再定义一个 left 和 right 指针,我们再看题目的一个要求是 nums[i] + nums[j] + nums[k] == 0,也就是说 nums[i] + nums[j] = - nums[k] ,我们就可以把 - nums[k] 当作 i 所指的固定数,那么,题目要求也就变成了 nums[left] + nums[right] = nums[i] 。

        在上面的基础上,left 在 i + 1 的位置开始,right 在 .length - 1 的位置开始,在 left 和 right 的区间不断判断 nums[left] + nums[right] = nums[i] 找到符合条件的三元组,其中要注意的是,如果是  nums[left] + nums[right] = nums[i] ,那么后续 letf 和 right 要各自跳过各自指向相同的元素,为什么呢?因为上面说过,“ 比如 [-1,0,1] 和 [ 0 , 1 ,-1] 是同一种,应当返回这两其中一个就行 ”。就以上图的举例,当前三元组可以[ -4 , 0 ,4] 符合条件,然后 left ++ ,right -- ,然后也是[ -4 , 0 ,4 ] ,这就不符合题目要求。

       然后再缩小区间继续判断直到当前 left 和 right 相遇结束,我们就解决了固定数字 i 指向的数字的三元组合,后续 i 要继续往后遍历其他的数字,注意,当前固定数字 i 指向的元素也不能重复,也需要跳过当前相同的元素。

三:代码实现

      //存储结果集
        List<List<Integer>> ret = new ArrayList<>();
 
        //排序数组
        Arrays.sort(nums);
 
        int n = nums.length;
        for(int i = 0; i < n; ) {
 
            //小优化
            if(nums[i] > 0) {
                break;
            }
 
            int left = i + 1;
            int right = n - 1;
 
            int sum = -nums[i];
 
            while(left < right) {
                if(nums[left] + nums[right] > sum) {
                    right--;
                }else if(nums[left] + nums[right] < sum) {
                    left++;
                }else {
                    //添加当前符合条件的三元组
                    ret.add(Arrays.asList(nums[i],nums[left],nums[right]));
 
                    left++;
                    right--;
 
                    //跳过 left 当前相同的元素
                    while(left < right && nums[left] == nums[left - 1]) {
                        left++;
                    }
 
                    //跳过 right 当前相同的元素
                     while(left < right && nums[right] == nums[right + 1]) {
                        right--;
                    }
 
                }
            }
 
            //处理重复的固定数字
            i++;
            while(i < n && nums[i] == nums[i - 1]) {
                i++;
            }
        }
 
        //返回结果集
        return ret;

        小优化那一段代码解释:如果当前 i 指向的元素大于 0 了 ,那么 sum 变量就是负数了 ,后续的 left 和 right 指针一定是在 i 的右边,left + right 指向的元素不可能为负数,就可以直接跳出固定数的循环了。

         处理重复的固定数字代码解释: i++ 后,先判断当前 i 的位置,再判断值是否与上一个元素相同。这样就可以避免如果当前 i 已经是越界了再访问数组的情况。

        为什么跳过 left 或 right 相同的元素的循环条件有 left < right,是因为避免一种极端情况,比如这样的数组 [0,0,0,0,0,0],如果不加上循环条件 left < right, left 会 不断 ++ 直到越界。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值