题目
给你一个长度为 n 的整数数组 nums和 一个目标值 target。请你从 nums中选出三个在 不同下标位置 的整数,使它们的和与 target 最接近。
返回这三个数的和。
假定每组输入只存在恰好一个解。
示例 1:
输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2)。
示例 2:
输入:nums = [0,0,0], target = 1
输出:0
解释:与 target 最接近的和是 0(0 + 0 + 0 = 0)。
Java语言
java
class Solution {
public int threeSumClosest(int[] nums, int target) {
Arrays.sort(nums);
int closest = nums[0] + nums[1] + nums[2]; // 初始用前三个数的和
for (int i = 0; i < nums.length - 2; i++) {
int left = i + 1, right = nums.length - 1;
while (left < right) {
int sum = nums[i] + nums[left] + nums[right];
int diff = sum - target;
// 比 closest 更接近 target 就更新
if (Math.abs(diff) < Math.abs(closest - target)) {
closest = sum;
}
if (diff < 0) {
left++; // 和太小,右移 left
} else if (diff > 0) {
right--; // 和太大,左移 right
} else {
return sum; // diff == 0,完美匹配,直接返回
}
}
}
return closest;
}
}
核心思路: 排序 + 双指针。和上一题(三数之和)一样的框架,但不再要求和恰好为 0,而是记录最接近 target 的和。
逐行说明:
java
Arrays.sort(nums);
int closest = nums[0] + nums[1] + nums[2];
先排序(双指针的前提)。closest 初始取前三个数的和,作为初始最接近值。
java
for (int i = 0; i < nums.length - 2; i++) {
遍历第一个数,到 length - 2 停止。
java
int left = i + 1, right = nums.length - 1;
while (left < right) {
int sum = nums[i] + nums[left] + nums[right];
int diff = sum - target;
双指针,计算三数之和与 target 的差值 diff。
java
if (Math.abs(diff) < Math.abs(closest - target)) {
closest = sum;
}
如果当前和与 target 的差距比之前记录的更小,就更新 closest。Math.abs() 取绝对值。
java
if (diff < 0) {
left++;
} else if (diff > 0) {
right--;
} else {
return sum;
}
diff < 0:和太小,left右移让和变大diff > 0:和太大,right左移让和变小diff == 0:和等于target,不可能更接近了,直接返回
java
return closest;
返回最接近的和。
与三数之和的区别:
| 特性 | 三数之和 (15题) | 最接近三数之和 (16题) |
|---|---|---|
| 目标 | 和恰好等于 0 | 和最接近 target |
| 去重 | 需要 | 不需要(只返回一个和) |
| 记录 | 所有满足条件的三元组 | 始终记录最接近的和 |
示例 1 演示: nums = [-1,2,1,-4] → 排序后 [-4,-1,1,2], target = 1
| i | numsi | left | right | sum | diff | closest | 操作 |
|---|---|---|---|---|---|---|---|
| 0 | -4 | 1 | 3 | -4+(-1)+2=-3 | -4 | -3 → abs=3 | 最初始 closest=-3, abs(-4)>abs(-4) 不更新, diff<0 left++ |
| 0 | -4 | 2 | 3 | -4+1+2=-1 | -2 | -1 → abs=2 | abs(-2) |
| 0 | -4 | 3 | 3 | left>=right 退出 | |||
| 1 | -1 | 2 | 3 | -1+1+2=2 | 1 | 2 → abs=1 | abs(1)0 right-- |
| 1 | -1 | 2 | 2 | left>=right 退出 |
最终返回 2 ✓
时间复杂度 O(n²),空间复杂度 O(1)(不计排序)。
python语言
python
class Solution(object):
def threeSumClosest(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
nums.sort()
closest = nums[0] + nums[1] + nums[2]
for i in range(len(nums) - 2):
left, right = i + 1, len(nums) - 1
while left < right:
total = nums[i] + nums[left] + nums[right]
diff = total - target
if abs(diff) < abs(closest - target):
closest = total
if diff < 0:
left += 1
elif diff > 0:
right -= 1
else:
return total
return closest
逻辑与 Java 版完全一致,逐行说明:
python
nums.sort()
closest = nums[0] + nums[1] + nums[2]
排序,初始最接近值取前三个数的和。nums.sort() 原地排序,对应 Java 的 Arrays.sort(nums)。
python
for i in range(len(nums) - 2):
left, right = i + 1, len(nums) - 1
遍历第一个数,双指针分别从 i+1 和末尾开始。left, right = i + 1, len(nums) - 1 一行同时赋值两个变量。
python
while left < right:
total = nums[i] + nums[left] + nums[right]
diff = total - target
计算三数之和与 target 的差值。
python
if abs(diff) < abs(closest - target):
closest = total
当前和更接近 target 就更新。abs() 取绝对值,对应 Java 的 Math.abs()。
python
if diff < 0:
left += 1
elif diff > 0:
right -= 1
else:
return total
diff < 0:和太小,left右移diff > 0:和太大,right左移diff == 0:完美匹配,直接返回
python
return closest
返回最接近的和。
与 Java 版的关键区别:
| 特性 | Java | Python |
|---|---|---|
| 排序 | Arrays.sort(nums) |
nums.sort() |
| 列表长度 | nums.length |
len(nums) |
| 绝对值 | Math.abs(x) |
abs(x) |
| 双变量赋值 | int left = a, right = b; |
left, right = a, b |
| 自增/自减 | left++ / right-- |
left += 1 / right -= 1 |
时间复杂度 O(n²),空间复杂度 O(1)(不计排序)。