LeetCode 16、最接近的三数之和

110 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第13天,点击查看活动详情

题目:给定一个数组nums和一个目标值target,要求从nums中选出三个数,使得其之和与target最近。

解题思路

要解决本题,首先需要回顾之前三数之和的解题方法,在计算三数之和时采用的是三指针,在计算之前需要对数组进行排序,之后第一个指针固定,之后第二个指针的开始是第一个指针的下一个元素,而第三个指针的开始则是数组的最后一个元素,计算这三个指针对应的数字之和,如果和相等则这是一个正确解,如果大于则代表第三个指针的数字需要变小,否则代表左边指针数字需要变大。如此循环即可,具体细节不再讨论。

本题的解决方法是在三数之和的基础上进行改造的,三数之和的思路本质上是对所有可能的结果进行了无重复判断,本题可使用两个变量来分别记录最小距离和相对应的值,每次计算三数之和,如果和target的距离等于0则此时必然是最小距离,直接返回结果即可,否则根据其大小进行左右指针的移动,如果遇到距离小于当前距离,则更新距离和对应的值,可得代码如下:

public int threeSumClosest(int[] nums, int target) {
    int distance = Integer.MAX_VALUE;
    int resSum = 0;
    Arrays.sort(nums);
    for(int i=0;i<nums.length-1;i++){
        if(i>0&&nums[i]==nums[i-1]) continue;
        int L = i+1;
        int R = nums.length-1;
        while(L<R){
            int temp = nums[i]+nums[L]+nums[R]-target;
            if(Math.abs(temp)<distance){
                distance = Math.abs(temp);
                resSum = nums[i]+nums[L]+nums[R];
            }
            if(temp==0) return resSum;
            if(temp>0){
                R--;
                while(L<R&&nums[R]==nums[R+1]) R--;
            }else {
                L++;
                while(L<R&&nums[L]==nums[L-1]) L++;
            }
        }
    }
    return resSum;
}

在距离大于0和小于0时,理论上移动后应该判断数组中是否存在相同元素,如果存在则应该跳过,但使用这个逻辑则耗时7ms,去除则耗时5ms,最后看了是因为每组输入都只存在恰好一个解,因此去除会快一点。