• Medium | LeetCode 15. 三数之和 | 双指针法


    15. 三数之和

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

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

    示例 1:

    输入:nums = [-1,0,1,2,-1,-4]
    输出:[[-1,-1,2],[-1,0,1]]
    

    示例 2:

    输入:nums = []
    输出:[]
    

    示例 3:

    输入:nums = [0]
    输出:[]
    

    提示:

    • 0 <= nums.length <= 3000
    • -105 <= nums[i] <= 105

    方法一:

    本题和 Easy | LeetCode 1. 两数之和 | 排序+双指针 | HaspMap 类似, 也可使用排序加双指针的方式。先排序, 然后从到右扫描数组, 找三数之和实际上就是找当前位置后面有没有两数之和为 target - num 的数组。

    由于题目不允许重复值。所以有两处需要跳过重复值。

    1. 在计算三数之和时, 对于当前值, 要跳过后面的重复值
    2. 在计算两数之和时, 由于采用的是双指针法, 既要跳过左指针的重复值, 也要跳过右指针的重复值。

    详细代码如下:

    public List<List<Integer>> threeSum(int[] nums) {
    	// 先排序
        Arrays.sort(nums);
        List<List<Integer>> res = new ArrayList<>();
        int target = 0;
        int i = 0;
        while (i < nums.length-1) {
            int firstValue = nums[i];
            // 将三数之和问题 转化为 两数之和 问题
            List<List<Integer>> twoSum = twoSum(nums, i + 1, target - firstValue);
            if (twoSum.size() > 0) {
                twoSum.forEach(twoSumList -> {
                    List<Integer> threeSum = new ArrayList<>();
                    threeSum.add(firstValue);
                    threeSum.addAll(twoSumList);
                    res.add(threeSum);
                });
            }
            // 同样扫描数组时, 要跳过重复值
            while (i < nums.length - 1 && nums[i] == firstValue) {
                i++;
            }
        }
        return res;
    }
    
    public List<List<Integer>> twoSum(int[] nums, int start, int target) {
        int left = start, right = nums.length -1;
        List<List<Integer>> res = new ArrayList<>();
        // 两数之和问题, 双指针法
        while (left < right) {
            int sum = nums[left] + nums[right];
            int leftValue = nums[left], rightValue = nums[right];
            if (sum < target) {
                // 当双指针之和小于目标值时, 左指针向前走
                left++;
            } else if (sum > target) {
                // 当双指针之和大于目标值时, 右指针向左走
                right--;
            } else {
                // 恰好等于目标值时, 先把当前答案添加进去
                List<Integer> twoSum = new ArrayList<>();
                twoSum.add(leftValue);
                twoSum.add(rightValue);
                res.add(twoSum);
                // 然后跳过左边的重复值, 因为题目不允许重复
                while (left < right && nums[left] == leftValue) {
                    left++;
                }
                // 跳过右边的重复值
                while (left < right && nums[right] == rightValue) {
                    right--;
                }
            }
        }
        return res;
    }
    
  • 相关阅读:
    js中的异常处理
    CSS3之box-sizing属性
    AJAX
    NaN与Null与undefiined的关系
    跳转语句之continue与break
    npm火速上手
    程序里面的‘脑筋急转弯’
    css伪元素::before与::after
    常用正则表达式、JS中的正则以及ES6的扩展
    git
  • 原文地址:https://www.cnblogs.com/chenrj97/p/14319439.html
Copyright © 2020-2023  润新知