leetcode
leetcode 2901 ~ 2950
三数之和

三数之和

难度:

标签:

题目描述

English description is not available for the problem. Please switch to Chinese.

代码结果

运行时间: 220 ms, 内存: 18.6 MB


/*
 * 思路:
 * 1. 使用Java Stream来简化代码流程。
 * 2. 首先对数组进行排序。
 * 3. 使用三指针方法,固定一个数,然后在剩余的数组中使用双指针来查找另外两个数。
 * 4. 遍历过程中,跳过重复的数以避免重复结果。
 */
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class ThreeSumStream {
    public List<List<Integer>> threeSum(int[] nums) {
        if (nums == null || nums.length < 3) return new ArrayList<>();
        Arrays.sort(nums); // 对数组进行排序
        return Arrays.stream(nums).boxed().flatMap(i -> {
            if (i > 0 && nums[i] == nums[i - 1]) return null; // 跳过重复的数
            int left = i + 1, right = nums.length - 1;
            List<List<Integer>> temp = new ArrayList<>();
            while (left < right) {
                int sum = nums[i] + nums[left] + nums[right];
                if (sum == 0) {
                    temp.add(Arrays.asList(nums[i], nums[left], nums[right]));
                    while (left < right && nums[left] == nums[left + 1]) left++; // 跳过重复的数
                    while (left < right && nums[right] == nums[right - 1]) right--; // 跳过重复的数
                    left++;
                    right--;
                } else if (sum < 0) {
                    left++;
                } else {
                    right--;
                }
            }
            return temp.stream();
        }).distinct().collect(Collectors.toList());
    }

    public static void main(String[] args) {
        ThreeSumStream solution = new ThreeSumStream();
        int[] nums = {-1, 0, 1, 2, -1, -4};
        System.out.println(solution.threeSum(nums)); // 输出: [[-1, -1, 2], [-1, 0, 1]]
    }
}

解释

方法:

此题解采用排序加双指针的方法解决三数之和问题。首先对数组进行排序,然后使用外层循环遍历每个数作为可能的三元组中的第一个数。对于每个选定的第一个数,使用内层的双指针来查找剩余两个数。如果三个数的和为零,则记录这个组合。为了避免重复的三元组,每次在找到有效的三元组后,需要跳过相同的数。同时,如果当前的数大于0,则可以直接终止循环,因为不可能再找到和为零的三元组。

时间复杂度:

O(n^2)

空间复杂度:

O(1)

代码细节讲解

🦆
为什么在遍历数组的过程中,当遇到第一个数大于0时,可以直接终止循环?
在排序后的数组中,一旦第一个数(即最小数)大于0,那么后面所有的数也都将大于0。因为三数之和要求的是和为0,所以当三个正数相加时,其结果必定大于0,不可能等于0。因此,当遍历到第一个数大于0时,可以肯定后续不会有任何三个数相加等于0的情况,直接终止循环是合理的。
🦆
在双指针中,如果左指针和右指针指向的元素和未达到目标值时,为什么只移动左指针而不考虑移动右指针?
在双指针策略中,当左右指针指向的元素的和小于目标值时,我们需要增加和的值以接近目标值。由于数组已经排序,右侧的指针指向的元素值较大,左侧的指针指向的元素值较小。因此,为了增加和的值,我们应该将左指针向右移动(即指向一个更大的值),而移动右指针(指向更小的值)会导致和的值减小,远离目标值。
🦆
在跳过重复数字时,你是如何确保不会漏掉任何有效的三元组解?
在找到一个有效的三元组后,为避免重复解,需要跳过所有与当前左指针或右指针值相同的元素。实现方法是在每次找到符合条件的三元组后,对左指针进行循环直到指向的下一个数与当前数不同,同理对右指针也做相同的处理。这样的跳过是在已经找到一个有效解之后进行的,因此不会漏掉任何解。此外,外层循环中也同样跳过了与前一个数相同的数,确保了每种可能的起始数只被使用一次,从而避免了从不同位置开始但内容相同的重复三元组。

相关问题