题目来自LeetCode,链接:3sum-closest。具体描述为:给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。
示例:
例如,给定数组 nums = [-1,2,1,-4], 和 target = 1.
与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2).
这跟前一道题/前一篇博客的三数之和解法很类似,可以套用那道题的解法。首先对数组排序,然后对于当前的数,其右边的数组成一个子数组(而且是升序的),给定左指针为子数组最左,右指针为子数组最右,左指针对应左数,右指针对应右数。利用一个变量记录最小误差。则:
- 计算三数之和与target的误差,若此误差的绝对值小于最小误差的绝对值,则更新最小误差为当前误差(可正可负);
- 如果三数之和=target,则直接返回target就行了;
- 如果三数之和<target,说明增大左数可能使得三数之和更靠近target,所以左指针右移;
- 否则即三数之和>target,说明减少右数可能使得三数之和更靠近target,所以右指针左移。
最后当前面的流程进行到左指针遇到/超过右指针就结束了,此时要把当前数右移到不与当前数相同位置,同样是为了避免重复。
最后需要返回的结果就是target+最小误差。
可以看到这种方法的时间复杂度同样为 O ( n 2 ) O(n^{2}) O(n2),空间复杂度为 O ( 1 ) O(1) O(1)。
JAVA版代码如下:
class Solution {
public int threeSumClosest(int[] nums, int target) {
int numsLen = nums.length;
Arrays.sort(nums);
int i = 0;
int minError = Integer.MAX_VALUE;
while (i < numsLen - 2) {
int left = i + 1;
int right = numsLen - 1;
while (left < right) {
int error = nums[i] + nums[left] + nums[right] - target;
if (Math.abs(error) < Math.abs(minError)) {
minError = error;
}
if (error == 0) {
return target;
}
else if (error < 0) {
++left;
}
else {
--right;
}
}
++i;
while (i < numsLen -2 && nums[i] == nums[i - 1]) {
++i;
}
}
return target + minError;
}
}
提交结果如下:
![](https://i-blog.csdnimg.cn/blog_migrate/9cdbe63dc88589fd80ee45742d0f792a.png)
Python版代码如下:
class Solution:
def threeSumClosest(self, nums: List[int], target: int) -> int:
nums.sort() #先升序排序
length = len(nums)
result = []
i = 0
minError = float('inf')
while i < length - 2: #只遍历到倒数第3个数
left = i + 1
right = length - 1
now_num = nums[i]
while left < right: #当左指针和右指针相遇就结束一轮循环
left_num = nums[left]
right_num = nums[right]
error = now_num + left_num + right_num - target
if abs(error) < abs(minError): #更新最小的误差绝对值
minError = error
if error == 0: #三个数的和为target
return target
elif error < 0: #当三个数的和小于target时,左指针右移
left += 1
else: #当三个数的和大于target时,右指针左移
right -= 1
i += 1
while i < length - 2 and nums[i] == now_num: #第一个数移动到不与之前一样为止
i += 1
return minError + target
提交结果如下:
![](https://i-blog.csdnimg.cn/blog_migrate/d753f4bba0e5d827260679f674b7425f.png)