57.三数之和

描述

给出一个有n个整数的数组S,在S中找到三个整数a, b, c,找到所有使得a + b + c = 0 的三元组

注意事项

在三元组(a, b, c),要求a <= b <= c。
结果不能包含重复的三元组。

注意

  1. 结果可能有多个解
  2. left和right分别指向的两个不同位置的元素值相同是允许的,两根指针允许同时出现相同的值
  3. i,left和right分别在遇到同一个值两次或两次以上要跳过,即去重,注意体会去重和2的区别,同一指针不允许连续出现一样的值

样例

如S = {-1 0 1 2 -1 -4}, 你需要返回的三元组集合的是:
(-1, 0, 1)
(-1, -1, 2)

思路

将数组排序,遍历数组每个元素,当前元素的负值做为target,在当前元素3后的所有元素中做寻找和为target的两个数

说明
三数之和中求两个数的和用两根指针来做时间复杂度为 O(nlogn),用两根指针的前提是数组先排好序,因为三数之和时间复杂度为 O(n^2) 就忽略了预先排序的时间开销,而在真正的两数之和为了追求 O(n) 的时间复杂度,我们用哈希表来做两数之和。
而且,三数之和实际上是在当前数 nums[i] 之后寻找满足条件的两个数,如果不用两根指针很难处理查找数组的范围变化

代码

public class Solution {
    /*
     * @param numbers: Give an array numbers of n integer
     * @return: Find all unique triplets in the array which gives the sum of zero.
     */
    public List> threeSum(int[] nums) {
        List> results = new ArrayList<>(); 

        // 注意异常的判断条件
        if (nums == null || nums.length < 3) {
            return results;
        }

        Arrays.sort(nums);

        // 边界条件
        for (int i = 0; i < nums.length - 2; i++) {
            if (i > 0 && nums[i] == nums[i - 1]) {
                continue;
            }
            int target = -nums[i];
            // left 是变量,left 之前的数在 i 的遍历中已经使用过了
            int left = i + 1;
            int right = nums.length - 1;
            twoSum(nums, left, right, target, results);
        }
        return results;
    }
    
    private void twoSum(int[] nums,
                        int left,
                        int right,
                        int target,
                        List> results) {
        while (left < right) {
            if (nums[left] + nums[right] == target) {
                List triple = new ArrayList<>();
                triple.add(-target);
                triple.add(nums[left]);
                triple.add(nums[right]);
                results.add(triple);
                // 此处的 left++ 和 right-- 不能忘记写
                left++;
                right--;
                while (left < right && nums[left] == nums[left - 1]) {
                    left++;
                }
                while (left < right && nums[right] == nums[right + 1]) {
                    right--;
                }
            } else if (nums[left] + nums[right] < target) {
                left++;
            } else {
                right--;
            }      
        }
    }
}

注:
如果 list 写在外面,在 twoSum 中传入,就会出现图片上的错误,所以要在33行下面新建 list


57.三数之和_第1张图片
two.jpeg

你可能感兴趣的:(57.三数之和)