问题
给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。
示例
例如,给定数组 nums = [-1,2,1,-4], 和 target = 1.
与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2).
自解
思路
与第15题三数之和类似。
暴力法时间复杂度为O(n3),故不考虑,使用双指针法减少计算量。
- 首先利用Array库的排序函数进行排序,之后遍历数组,,用两个指针l和r进行选择,初始l=i+1,r=(nums的长度)-1。
- 计算nums[i] + nums[l] + nums[r]和target相减的绝对值,在aAbs中存储最小的绝对值,将计算结果和aAbs中的值对比若小于则替换aAbs的值以及把相加最接近结果赋值给ans。若相加结果大于target则说明右指针所指的数太大应将r的值减一;若其小于target则说明左指针所指的数太小应将l的值加一。
- 其中应注意对重复数字的处理。
if (i > 0 && nums[i] == nums[i-1])
代码
class Solution {
public int threeSumClosest(int[] nums, int target) {
Arrays.sort(nums);
int len = nums.length;
int add = 0, aAbs = Integer.MAX_VALUE, ans = 0;
for (int i = 0; i < len; i++) {
if (i > 0 && nums[i] == nums[i-1])
continue;
int l = i + 1;
int r = len - 1;
while (r > l) {
add = nums[i] + nums[l] + nums[r];
if (Math.abs(add - target) < aAbs) {
aAbs = Math.abs(add - target);
ans = add;
}
if (add > target)
r--;
else if (add < target)
l++;
else
return add;
}
}
return ans;
}
}
结果
补充
Array.sort()
函数使用的是快速排序,时间复杂度为O(nlogn),之后遍历数组时间复杂度为O(n2),总时间复杂度为O(n2)。
- 微软MSDN上对System.Array.Sort的说明:
“Array 中的每个元素均必须实现 IComparable 接口,才能与 array 中的其他所有元素进行比较。如果排序不能成功地完成,则结果未定义。此方法使用 QuickSort 算法。此实现执行不稳定排序;亦即,如果两元素相等,则其顺序可能不被保留。相反,稳定排序保留相等元素的顺序。 一般情况下,此方法的运算复杂度为 O(n log n),其中 n 是 array 的 Length;最坏的情况下其运算复杂度为 O(n ^ 2)。”