15. 三数之和

63 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第11天,点击查看活动详情

题目描述

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请

你返回所有和为 0 且不重复的三元组。

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

示例 1:

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1][-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。

示例 2:

输入:nums = [0,1,1]
输出:[]
解释:唯一可能的三元组和不为 0 。

示例 3:

输入:nums = [0,0,0]
输出:[[0,0,0]]
解释:唯一可能的三元组和为 0

提示:

3 <= nums.length <= 3000
-105 <= nums[i] <= 10^5

解题思路

题目长度为3000,表示我们可以用双重循环。用暴力的三重循环判断三者相加是否等于target直接会超时。 做两数之和的时候我们是先用set来保存数字,再遍历一遍看是否有与之对应的值;

这题我们也可以是这个思路,只不过稍有不同,先将数组排序,在一重循环里先确定一个值num,接着任务就是去找两数之后为-num的值,因为已经排序了,我们就可以用双指针left,right,如果nums[left]+nums[right]大于-num,就把right下标减一,小于就把left+1,等于-num表示找到一组值。

代码

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        int n = nums.length;
        Arrays.sort(nums);
        List<List<Integer>> ans = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            if (i > 0 && nums[i] == nums[i - 1]) continue; // 当前数和上一个数一样,直接跳过
            int target = -nums[i]; // 现在的目的就是要找两个数的和为target的了
            int left = i + 1,right = n - 1; // 双指针的下标
            while (left < right) {
                // 也是当前数等于上一个数
                if (left > i + 1 && nums[left] == nums[left - 1]) {
                    left ++;
                    continue; 
                }
                if (right < n - 1 && nums[right] == nums[right + 1]) {
                    right --;
                    continue;
                }
                // 当前的数大于目标值,减小当前数,right右移
                if (nums[left] + nums[right] > target) {
                    right--;
                } else if(nums[left] + nums[right] < target) {
                    left ++;
                } else { // 找到三数了 
                    List<Integer> list = new ArrayList<>();
                    list.add(nums[i]);
                    list.add(nums[left]);
                    list.add(nums[right]);
                    ans.add(list);
                    left++;
                    right--;
                }
            }
        }
        return ans;
    }
}

image.png