LeetCode第16题思悟——最接近的三数之和(3sum-closest)

LeetCode第16题思悟——最接近的三数之和(3sum-closest)

文章目录

  • LeetCode第16题思悟——最接近的三数之和(3sum-closest)
    • 知识点预告
    • 题目要求
    • 示例
    • 我的思路
    • 优秀解法
    • 差异分析
    • 知识点回顾

知识点预告

  1. 数组预处理:排序;
  2. 双指针遍历数组的处理方法;

题目要求

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/3sum-closest
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

示例

给定数组 nums = [-1,2,1,-4], 和 target = 1.

与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2).

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/3sum-closest
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

我的思路

排序后三重循环。需要注意的是去重;基本操作;

public static int threeSumClosest(int[] nums, int target) {
    if(nums.length==3){
        return nums[0]+nums[1]+nums[2];
    }
    Arrays.sort(nums);
    int minDifference=Integer.MAX_VALUE;
    int numLength=nums.length;
    int secondStartPoint,thirdStartPoint;
    int currentDifference;
    int lastMinDifference;
    int firstNum;
    int secondNum;
    int currentSum;
    int result=0;
    int firstBorder=numLength-2;
    int secondBorder=numLength-1;
    boolean hasSkip;
    for(int i=0;i<firstBorder;i++){
        firstNum=nums[i];
        secondStartPoint=i+1;
        hasSkip=false;
        for(int j=secondStartPoint;j<secondBorder;j++){
            secondNum=nums[j];
            thirdStartPoint=j+1;
			lastMinDifference=Integer.MAX_VALUE;
            for(int k=thirdStartPoint;k<numLength;k++){
                currentSum=firstNum+secondNum+nums[k];
                currentDifference=Math.abs(target-currentSum);
                if(currentDifference<minDifference){
                    minDifference=currentDifference;
                    result=currentSum;
                }
                if(currentDifference<=lastMinDifference){
                	lastMinDifference=currentDifference;
				}else{
                	System.out.println("Break");
                	break;
				}
            }
        }
        //跳过第一个
        while(i<firstBorder&&nums[i]==firstNum){
            i++;
            hasSkip=true;
        }
        if(hasSkip){
        	i--;
		}
    }
    return result;
}

经过LeetCode第15题思悟,我们知道,可以使用双指针遍历的方法替代内部的双重循环;

优秀解法

//解法A
public int threeSumClosest(int[] nums, int target) {
	Arrays.sort(nums);
	int ans = nums[0] + nums[1] + nums[2];
	for (int i = 0; i < nums.length; i++) {
		int start = i + 1, end = nums.length - 1;
		while (start < end) {
			int sum = nums[start] + nums[end] + nums[i];
			if (Math.abs(target - sum) < Math.abs(target - ans))
				ans = sum;
			if (sum > target)
				end--;
			else if (sum < target)
				start++;
			else
				return ans;
		}
	}
	return ans;
}
//解法B
public static int threeSumClosest(int[] nums, int target) {
	Arrays.sort(nums);
	int res = 0;
	for (int i = nums.length - 1; i >= nums.length - 3; i--) {
		res += Math.abs(nums[i]);
	}//Fragment B
	if(nums.length == 3)
		return nums[0] + nums[1] + nums[2];
	for(int i = 0; i <= nums.length - 2; i++) {
		for(int l = i + 1, r = nums.length - 1, sum = 0; l < r;) {
			sum = nums[i] + nums[l] + nums[r];
			if(Math.abs(sum - target) <= Math.abs(res - target))
				res = sum;
			if(sum > target) {
				r --;
			}else if(sum < target) {
				l ++;
			}else {
				return res;
			}
		}
	}
	return res;
}

差异分析

解法A和解法B的本质是相同的,都是使用双指针遍历数组来实现双重循环的功能;

但是Fragment B的目的是初始化res,但遍历整个数组是没有必要的:只需要将其初始化为数组前三个元素之和即可;对于较大长度的数组来说,也能节约一定时间吧;

知识点回顾

  1. 数组预处理:排序;
  2. 双指针遍历数组的处理方法;

你可能感兴趣的:(LeetCode思悟)