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;
}
}
}