题目描述
给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。
- 示例1:
输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。
提示:
3 <= nums.length <= 103
-103 <= nums[i] <= 103
-104 <= target <= 104
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/3sum-closest
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路
三个数看似要做三重循环,但是实际上是可以优化成两层循环的,优化的前提是有序,因此第一步先把数组进行升序排序。再设置一个记录最小差值的变量diff和一个记录差值正负的变量pos。
然后,先确定第一个数,第一个数的遍历范围为0~n-2;再确定后面两个数,其中的第一个数的遍历范围为1~n-1,第二个数的遍历范围为n~2(注意这个数是倒着遍历的),这两个数是同时遍历的,也可以说是双指针p和q,循环终止的条件是 p >= q。
取更小的差值绝对值来不断更新diff
- 若 nums[i] + nums[p] + nums[q] == target,则直接返回target
- 若 nums[i] + nums[p] + nums[q] < target,说明 p 指向的数字过小,p指向下一个数字,pos置false,代表差值为负
- 若 nums[i] + nums[p] + nums[q] > target,说明 q 指向的数字过大,q指向下一个数字,pos置true,代表差值为正
若pos为true,则最后返回target+diff,反之则返回target-diff
代码详解
class Solution {
public int threeSumClosest(int[] nums, int target) {
Arrays.sort(nums); // 先排序
int diff = Integer.MAX_VALUE;
boolean pos = true; // 记录差值正负
for(int i = 0; i < nums.length - 2; ++i) {
int p = i + 1;
int q = nums.length - 1;
while(p < q) {
if(Math.abs(nums[i] + nums[p] + nums[q] - target) < diff) {
diff = Math.abs(nums[i] + nums[p] + nums[q] - target); // 更新最小差值的绝对值
// 更新正负
if(nums[i] + nums[p] + nums[q] > target) {
pos = true;
} else if(nums[i] + nums[p] + nums[q] < target) {
pos = false;
}
}
// 双指针的移动
if(nums[i] + nums[p] + nums[q] > target) {
--q;
} else if(nums[i] + nums[p] + nums[q] < target) {
++p;
} else {
return target;
}
}
}
return target + (pos ? diff : -diff);
}
}