LeetCode 15.三数之和

题目:

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

思路:

  • 最基本的做法就是三重for循环暴力解法,但是这样时间复杂度O(n^3),太慢了
  • 我们可以使用排序+双指针的方式降低时间复杂度
  1. 首先我们先将数组按照从小到大的顺序排序
  2. 第一重循环还是遍历第一个元素i,并设置一个target=-nums[i],也就是后两个元素的和应该等于target才能保证三数之和为0
  3. 第二重循环遍历第二个元素j,与此同时,在第二个元素的遍历过程中,我们将第三个元素k从后向前遍历,因为数组元素是递增的,如果第二个元素过大,那么就要让第三个元素变小,才能保证两数之和等于target,且他是从结尾元素开始的,因此要向前走
  4. 如果我们碰到随着一个元素的增大会导致另一个元素的缩小,那么就可以尝试使用双指针来做
  5. 这样一来,第二个元素的遍历和第三个元素的遍历其实是同步进行的,再加上第一个元素的一重遍历,整个时间复杂度就变成了:O(n^2)

以下为代码+注释,其中还有一些细节:


public List<List<Integer>> threeSum(int[] nums) {
        // 双指针
        List<List<Integer>> res = new ArrayList<List<Integer>>();
        int len = nums.length;
        // 将数组元素按照从小到大排序
        Arrays.sort(nums);
        for(int i = 0; i < len; i++){
            // 如果当前首元素和上一个相同,因为要求不能出现重复的三元组,所以直接进行下一次循环,
            if(i > 0 && nums[i] == nums[i - 1])
                continue;
            // 设置后两个元素之和要达到的目标值
            int target = -nums[i];
            // 设置第三个元素的指针从尾部开始走
            int k = len - 1;
            for(int j = i + 1; j < len; j++){
            	//保证当前元素和上一个元素值不相同,因为不能出现重复三元组
                if(j != i + 1 && nums[j] == nums[j - 1])
                    continue;
                // 如果当前后两个元素的和大于target,需要让第三个元素向前移动找小的值
                // 因为数组是增序排列的
                while(j < k && nums[j] + nums[k] > target)
                    k--;
                // 如果走到第二个元素和第三个元素重合了都没找到和等于target的,说明后续的值都大于target
                // 第二个元素j再向后走也没用了,和第三个元素的和只会更大,直接跳出循环
                if(j == k)
                    break;
                // 如果后两个元素和为target,说明该情况符合,加入集合
                if(nums[j] + nums[k] == target){
                    List<Integer> list = new ArrayList<>();
                    list.add(nums[i]);
                    list.add(nums[j]);
                    list.add(nums[k]);
                    res.add(list);
                }
            }
        }
        return res;
    }

笔者也在不断学习,如有错误,欢迎指正!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值