LeetCode16 3Sum Closest(最接近的三数之和) JAVA实现

给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。

例如,给定数组 nums = [-1,2,1,-4], 和 target = 1. 与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2).

解题思路:

参考: leetcode 15 三数之和 3Sum JAVA实现

LeetCode18. 四数之和 4Sum JAVA实现

由于已经做过了15题 三数之和。本题的思路可以仿照15的题的思路,将三数之和问题间接转变为二数之和,利用双指针再次减少比较次数。

先将数组进行排序,如给定的数组 nums = [-1,2,1,-4], 和 target = 1.

排序后的结果为 nums = [-4,-1,1,2]

令i从0循环到nums.length-2,l=i+1,r=nums.length-1.

a = nums[i] ; b = nums[l]; c = nums[r];

需要用变量sum记录下a+b+c之和,sum = a+b+c;

需要用变量min记录下a+b+c与target的最小距离,min = Math.abs(sum -target);并且在每一次更新sum后进行判断是否更新min的值。

如果sum>target的值,那么r应该左移

如果sum<target的值,那么l应该右移

考虑一下特殊情况,当nums数组不足三个元素时,默认返回target;当nums数组仅有三个元素时,则直接返回nums[0]+nums[1]+nums[2]

我在这里写了一个与15题非常镜像的程序

class Solution {
    public int threeSumClosest(int[] nums, int target) {
        if(nums.length < 3)//数组不足三个元素
            return target;
        if(nums.length == 3){//数组仅有三个元素
            return nums[0]+nums[1]+nums[2];
        }
        Arrays.sort(nums);//将数组排序
        int min = Integer.MAX_VALUE;//记录 a+b+c - target的最短距离
        int res = 0;//记录结果sum值
        for(int i=0;i<nums.length-2;i++){
            int a = nums[i];
            int l = i+1;
            int r = nums.length-1;
            int sum = 0;
            int dif = 0;
            while(l<r){
                sum = a+nums[l]+nums[r];
                dif = Math.abs(sum-target);
                if(dif == 0)//如果sum==target
                    return target;
                if(dif<=min){//如果需要更新min的值
                    min = dif;
                    res = sum;
                    if(sum < target){//sum<target l左移
                        while(l<r && nums[l]==nums[l+1]) l++; //跳过重复
                        l++;
                    }else if(sum > target){//sum>target r右移
                        while(l<r && nums[r] == nums[r-1]) r--; //跳过重复
                        r--;
                    }
                }
                else{//不需要更新min值
                    if(sum < target){
                        while(l<r && nums[l]==nums[l+1]) l++;
                        l++;
                    }else if(sum > target){
                        while(l<r && nums[r] == nums[r-1]) r--;
                        r--;
                    }
                }
            }
        }
        return res;
    }
}

代码耗时25ms

这个代码实在太臃肿了,考虑进行优化。

  1. 1 这个题和15题的区别是 该题是唯一解,因此不必判重,判重的代价太大。
  2. 2 l和r的移动应该和是否更新min值分开
  3. 3 考虑这种情况,如果nums[i]+nums[nums.length-2]+nums[nums.length-1]<target,那么此时该范围已经不可能存在大于nums[i]+nums[nums.length-2]+nums[nums.length-1]的数了,则i应该继续移动,才能保证可能找到更接近target的数。
  4. 4 再考虑这种情况,nums[i]+nums[i+1]+nums[i+2] > target,此时无论i,l,r怎样继续移动,只可能存在比nums[i]+nums[i+1]+nums[i+2]大的数,所以此时直接返回当前的res值,结束程序。

优化后的下述代码耗时12ms

class Solution {
    public int threeSumClosest(int[] nums, int target) {
        if(nums.length < 3)//数组不足三个元素
            return target;
        else if(nums.length == 3){//数组仅有三个元素
            return nums[0]+nums[1]+nums[2];
        }
        else{
            Arrays.sort(nums);//将数组排序
            int min = Integer.MAX_VALUE;//记录 a+b+c - target的最短距离
            int res = 0;//记录结果sum值
            for(int i=0;i<nums.length-2;i++){
                int l = i+1;
                int r = nums.length-1;
                int sum = 0;
                int dif = 0;
                if(nums[i]+nums[nums.length-2]+nums[nums.length-1]<target){
                    sum = nums[i]+nums[nums.length-2]+nums[nums.length-1];
                    dif = Math.abs(sum-target);
                    if(dif<min){
                        min = dif;
                        res = sum;
                    }
                    continue;
                }
                if(nums[i]+nums[i+1]+nums[i+2] > target){
                    sum = nums[i]+nums[i+1]+nums[i+2];
                    dif = Math.abs(sum-target);
                    if(dif<min){
                        min = dif;
                        res = sum;
                    }
                    return res;
                }
                while(l<r){
                    sum = nums[i]+nums[l]+nums[r];
                    dif = Math.abs(sum-target);
                    if(dif == 0)//如果sum==target
                        return target;
                    if(dif<min){//如果需要更新min的值
                        min = dif;
                        res = sum;
                    }
                    if(sum < target)//sum<target l左移
                            l++;
                    else if(sum > target)//sum>target r右移
                            r--;
                    }
            }
            return res;
        } 
    }
}

最后贴上排名第一的答案,耗时8ms

class Solution {
    public int threeSumClosest(int[] nums, int target) {
        if(nums.length<3){
            return target;
        }
        else if (nums.length==3){
            return nums[0] +  nums[1] + nums[2];
        }
        else{
            int result= nums[0] + nums[1] + nums[2];
            int cSum;
            Arrays.sort(nums);
            for(int i=0; i<nums.length-2; i++){
                int j=i+1;
                int k=nums.length-1;
                if((nums[i] + nums[nums.length-2] + nums[nums.length-1])<target){
                    cSum = nums[i] + nums[nums.length-2] + nums[nums.length-1];
                    result = check(target, result, cSum);
                    continue;
                }
                if((nums[i] + nums[i+1] + nums[i+2])>target){
                    cSum = nums[i] + nums[i+1] + nums[i+2];
                    result = check(target, result, cSum);
                    continue;
                }
                while(j<k){
                    cSum = nums[i] + nums[j] + nums[k];
                    if(cSum == target){
                        return cSum;
                    }
                    result = check(target, result, cSum);
                    if(cSum < target){
                        j++;
                    }
                    else if(cSum > target){
                        k--;
                    }
                }
            }
            return result;
        }
        
        
    }
    private int check(int target, int result, int cSum){
        if(Math.abs(target - cSum)<Math.abs(target - result)){
            result = cSum;
        }
        return result;
    }
}

猜你喜欢

转载自blog.csdn.net/qq_25406563/article/details/88035503
今日推荐