15. 三数之和

题目

15. 三数之和

要求

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != 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] <= 105

思考

三数之和,先借用两数之和的思路,看看如下代码:

public List<List<Integer>> threeSum(int[] nums) {
    Set<List<Integer>> result = new HashSet<>();
    for (int i = 0; i < nums.length; i++) {
				// 重复判断,减少了 while 循环的次数
        if (i > 0 && nums[i] == nums[i - 1]) {
            continue;
        }
        List<List<Integer>> list = myTwoSum(nums, -nums[i], i);
        for (int j = 0; j < list.size(); j++) {
            list.get(j).add(nums[i]);
            // 排序,外部 set 去重
            Collections.sort(list.get(j));
        }
        if (!list.isEmpty()) {
            result.addAll(list);
        }
    }
    return new ArrayList<>(result);
}

private List<List<Integer>> myTwoSum(int[] nums, int target, int index) {
    List<List<Integer>> result = new ArrayList<>();
    HashSet<Integer> set = new HashSet<>();
    for (int i = index + 1; i < nums.length; i++) {
        if (set.contains(target - nums[i])) {
            List<Integer> temp = new ArrayList<>();
            temp.add(nums[i]);
            temp.add(target - nums[i]);
            result.add(temp);
        }
        set.add(nums[i]);
    }
    return result;
}

这个写法只能说正确,但是效率就不多说呢,能通过。

继续思考,数组的题目,可以想想排序,排序 + 双指针呢?双指针的的思路是在排序的基础上才可以实现的,排序之后遍历每一位,双指针分别是当前遍历的下一位和最后一位,和大于 0 移动 right,和小于 0 移动 left,等于 0 就记录,代码如下:

public List<List<Integer>> threeSum(int[] nums) {
    Set<List<Integer>> result = new HashSet<>();
    Arrays.sort(nums);
    for (int i = 0; i < nums.length; i++) {
        // 重复判断,减少了 while 循环的次数
        if (i > 0 && nums[i] == nums[i - 1]) {
            continue;
        }
        int left = i + 1;
        int right = nums.length - 1;
        while (left < right) {
            if (nums[i] + nums[left] + nums[right] == 0) {
                result.add(Arrays.asList(nums[i], nums[left], nums[right]));
                left ++;
                right --;
            } else if (nums[i] + nums[left] + nums[right] > 0) {
                right --;
            } else {
                left ++;
            }
        }
    }
    return new ArrayList<>(result);
}

三数之和可以这么做,那四数之和呢?

posted @ 2023-12-19 11:19  庄子游世  阅读(2)  评论(0编辑  收藏  举报