Leetcode力扣秋招刷题路-0016

从0开始的秋招刷题路,记录下所刷每道题的题解,帮助自己回顾总结

16. 最接近的三数之和

给你一个长度为 n 的整数数组 nums 和 一个目标值 target。请你从 nums 中选出三个整数,使它们的和与 target 最接近。
返回这三个数的和。
假定每组输入只存在恰好一个解。

示例 1:
输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。

示例 2:
输入:nums = [0,0,0], target = 1
输出:0

提示:
3 <= nums.length <= 1000
-1000 <= nums[i] <= 1000
− 1 0 4 -10^4 104 <= target <= 1 0 4 10^4 104

题意分析: (1) 三数之和最接近目标值,就表示三数之和减去目标值的绝对值最小。 (2) 将一个数组排序以后,三数之和的大小边界就是开始的三个数之和和结尾的三个数之和。 本题需要注意的就是要避免重复遍历和无效遍历的运算。

方法一:双指针 思路: (1) 循环选择固定第一个数,然后通过双指针遍历另外两个数。 (2) 通过剪枝跳过重复遍历,完成所有遍历得到最接近的结果。

class Solution {
    public int threeSumClosest(int[] nums, int target) {
        // 初始化 ans 为边界值,表示离 target 最远的和。
        int ans = Integer.MIN_VALUE;
        int len = nums.length;
        if (len < 3) {
            throw new IllegalArgumentException("数组元素不够三个!");
        }
        // 对数组排序,方便双指针移动。
        Arrays.sort(nums);
        // 判断 target 如果在数组和的边界之外则直接返回边界值。
        if (target <= nums[0] + nums[1] + nums[2]) {
            return nums[0] + nums[1] + nums[2];
        } else if (target >= nums[len - 1] + nums[len - 2] + nums[len - 3]){
            return nums[len - 1] + nums[len - 2] + nums[len - 3];
        }
        // 循环固定第一个数,根据双指针从它之后去选择另外两个数。
        for (int i = 0; i < len - 2; i++) {
            // 相同的第一个数只固定一次,避免重复运算。
            if (i > 0 && nums[i] == nums[i - 1]) {
                continue;
            }
            int L = i + 1, R = len - 1;
            while (L < R) {
                // 判断当前循环能得到的最小三数和。
                int min = nums[i] + nums[L] + nums[L + 1];
                if (target < min) {
                    if (Math.abs(ans - target) > Math.abs(min - target)) {
                        ans = min;
                    }
                    break;
                }
                // 判断当前循环能得到的最大三数和。
                int max = nums[i] + nums[R] + nums[R - 1];
                if (target > max) {
                    if (Math.abs(ans - target) > Math.abs(max - target)) {
                        ans = max;
                    }
                    break;
                }
                int sum = nums[i] + nums[L] + nums[R];
                // 如果三数之和等于 target 则直接返回。
                if (sum == target) {
                    return sum;
                }
                // 根据差的绝对值判断离 target 最近的和。
                if (Math.abs(target - sum) < Math.abs(target - ans)) {
                    ans = sum;
                }
                // 根据三数之和与 target 大小的比较来移动俩指针。
                if (sum > target) {
                    R--;
                    while (L < R && nums[R + 1] == nums[R]) {
                        R--;
                    }
                } else {
                    L++;
                    while (L < R && nums[L - 1] == nums[L]) {
                        L++;
                    }
                }
            }
        }
        return ans;
    }
}

你可能感兴趣的:(Leetcode,leetcode,算法,数据结构)