给定一个数组 nums 和一个目标值 target ,请问从 nums 中选出三个数,使其之和尽量接近目标数,即三数之和与目标数只差绝对值尽可能小。
返回满足题面要求的三数之和。
数据范围:数组长度满足
,数组中的值满足
,目标值满足
,可以保证只有一个结果。
[-1,2,1,-4],1
2
最接近 1 的三数之和是 -1+2+1 = 2
[0,0,0],1
0
只有一种选择 0+0+0
[0,1,0,0],0
0
import java.util.*; /** * NC247 最接近的三数之和 * @author d3y1 */ public class Solution { private int sum; private int abs; private int diff = Integer.MAX_VALUE; private int result; /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param nums int整型一维数组 * @param target int整型 * @return int整型 */ public int ClosestSum (int[] nums, int target) { // return solution1(nums, target); return solution2(nums, target); // return solution3(nums, target); // return solution4(nums, target); } /** * 排序+三指针 * @param nums * @param target * @return */ private int solution1(int[] nums, int target){ int n = nums.length; // 排序 Arrays.sort(nums); // 三指针 for(int i=0; i<=n-3; i++){ for(int j=i+1; j<=n-2; j++){ for(int k=j+1; k<=n-1; k++){ check(nums, target, i, j, k); if(sum == target){ return sum; }else if(sum > target){ break; } } } } return result; } /** * 排序+三指针: 优化 * @param nums * @param target * @return */ private int solution2(int[] nums, int target){ int n = nums.length; // 排序 Arrays.sort(nums); // 三指针 int j,k; for(int i=0; i<=n-3; i++){ j = i+1; k = n-1; while(j < k){ check(nums, target, i, j, k); if(sum < target){ j++; } else if(sum > target){ k--; }else{ return sum; } } } return result; } /** * 排序+双指针+二分 * @param nums * @param target * @return */ private int solution3(int[] nums, int target){ int n = nums.length; // 排序 Arrays.sort(nums); // 双指针+二分 for(int i=0; i<=n-3; i++){ for(int j=i+1; j<=n-2; j++){ int left = j+1; int right = n-1; int mid; while(left <= right){ mid = left+((right-left)>>1); sum = nums[i]+nums[j]+nums[mid]; if(sum < target){ left = mid+1; }else if(sum > target){ right = mid-1; }else{ return sum; } } // 左边界 if(left == j+1){ check(nums, target, i, j, j+1); } // 右边界 else if(left == n){ check(nums, target, i, j, n-1); } // 中间 else{ check(nums, target, i, j, left-1); check(nums, target, i, j, left); } } } return result; } /** * 递归: 遍历解空间 * @param nums * @param target * @return */ private int solution4(int[] nums, int target){ adder(nums, target, 0, 0, 0); return result; } /** * 递归: 加法器 * @param nums * @param target * @param index * @param cnt * @param sum */ private void adder(int[] nums, int target, int index, int cnt, int sum){ if(index >= nums.length){ return; } if(cnt == 3){ abs = Math.abs(sum-target); if(abs < diff){ result = sum; diff = abs; } return; } for(int i=index; i<nums.length; i++){ adder(nums, target, i+1, cnt+1, sum+nums[i]); } } /** * 差值校验 * @param nums * @param target * @param i * @param j * @param k */ private void check(int[] nums, int target, int i, int j, int k){ sum = nums[i]+nums[j]+nums[k]; abs = Math.abs(sum-target); if(abs < diff){ result = sum; diff = abs; } } }
public class Solution { public int ClosestSum (int[] nums, int target) { Arrays.sort(nums); int min = Integer.MAX_VALUE, res = 0; for (int i = 0; i < nums.length-2; i++) { if (i > 0 && nums[i] == nums[i-1]) continue; int start = i + 1, end = nums.length-1, sum = 0, dif = 0; while (start < end) { sum = nums[i] + nums[start] + nums[end]; dif = Math.abs(sum-target); if (dif < min) { min = dif; res = sum; } if (sum > target) { end--; while (start < end && nums[end+1]== nums[end]) end--; } else if (sum < target) { start++; while (start < end && nums[start-1]== nums[start]) start++; } else return target; } } return res; } }