LeetCode 15. 三数之和

72 篇文章 0 订阅
15. 三数之和

难度 中等

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 *a,b,c ,*使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。

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

示例 1:

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]

示例 2:

输入:nums = []
输出:[]

示例 3:

输入:nums = [0]
输出:[]

提示:

  • 0 <= nums.length <= 3000
  • -105 <= nums[i] <= 105

题解

​ 这道题看着提容易理解,但是实际上不是很好解,三次方不满足时间复杂度,所以必须想办法优化。像官方题解,先选定一个数,然后还需要选定两个数,这样就像167. 两数之和 II - 输入有序数组了,但是还有一个问题,这里的数字可以重复,出现同样的答案,需要去重。

  • 第一种做法,找出所有结果之后,然后去重。这种做法解题过程比较简单,但是去重效率低。

  • 第二种做法,在解题的时候去重。反过来,解题过程比较复杂,不需要去重。

    ​ 那在解题的过程怎么去重,如果选的第一个数是1,第二个数也是1,第三个数是-2,假设数组是[1,1,1,1,1,1,1,1,1,-2],那么会有很多重复的结果。如果我们限制选了第一个数,之后,我们第二个数的选取要加以限制,必须与前一个数不相等。比如,第一个数选取了下标为0的数1,第二个数选取了下标为1的数1,第三个数选取了最后一个数-2,有了第一个结果[1,1,-2],那么第二个数选取范围从1到8之间的所有1构成的结果都是一样的,我们只要加以限制不可以选取与前一个数相同的数就行(nums[second] != nums[second - 1])。

    ​ 类似的,第一个数也是这样,不能选取与前一个数相同的数,因为前一个数已经枚举完所有这个数可能的结果。

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        int n = nums.length;//数组长度
        Arrays.sort(nums);//排序,变为升序数组
        List<List<Integer>> ans = new ArrayList<List<Integer>>();//存储答案
        for(int first = 0; first < n; first++){//枚举第一个数
            if(first > 0 && nums[first] == nums[first - 1]){//如果枚举的数和前一个数相同,跳过循环
                continue;
            }
            int third = n - 1;//从后面开始枚举
            int target = -nums[first];//a+b+c=0,移项,b+c=-a
            for(int second = first + 1; second < n; second++){//枚举第二个数
                if(second > first + 1 && nums[second] == nums[second - 1]){//如果枚举的数和前一个数相同,跳过循环
                    continue;
                }
                while(second < third && nums[second] + nums[third] > target){//如果两个数之后大于target,第三个数后迁移
                    --third;
                }
                if(second == third){//下标相同,结束循环
                    break;
                }
                if(nums[second] + nums[third] == target){//找到结果
                    List<Integer> list = new ArrayList<Integer>();
                    list.add(nums[first]);
                    list.add(nums[second]);
                    list.add(nums[third]);
                    ans.add(list);
                }
            }
        }
        return ans;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值