Medium
题目描述
给你一个长度为 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) 。
提示:
3 <= nums.length <= 500-1000 <= nums[i] <= 1000-10^4 <= target <= 10^4
解题思路
这道题是经典的三指针问题,可以通过排序 + 双指针的方式高效求解。
基本思路:
- 首先对数组进行排序,这样可以使用双指针技巧
- 固定第一个数,然后用双指针在剩余数组中寻找最接近目标值的两数之和
- 维护一个全局的最接近值,不断更新
具体步骤:
- 对数组排序
- 遍历数组,固定第一个元素
nums[i] - 设置左指针
left = i + 1,右指针right = n - 1 - 计算三数之和
sum = nums[i] + nums[left] + nums[right] - 如果当前和比之前记录的更接近目标值,则更新结果
- 根据和与目标值的关系调整指针:
- 如果
sum < target,说明和太小,左指针右移 - 如果
sum > target,说明和太大,右指针左移 - 如果
sum == target,直接返回(找到最接近的解)
- 如果
时间复杂度优化: 可以通过跳过重复元素来避免不必要的计算。
这种方法比暴力枚举所有三元组的 O(n³) 解法更加高效。
代码实现
class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
sort(nums.begin(), nums.end());
int n = nums.size();
int closest = nums[0] + nums[1] + nums[2];
for (int i = 0; i < n - 2; i++) {
int left = i + 1, right = n - 1;
while (left < right) {
int sum = nums[i] + nums[left] + nums[right];
if (abs(sum - target) < abs(closest - target)) {
closest = sum;
}
if (sum < target) {
left++;
} else if (sum > target) {
right--;
} else {
return sum;
}
}
}
return closest;
}
};
class Solution:
def threeSumClosest(self, nums: List[int], target: int) -> int:
nums.sort()
n = len(nums)
closest = nums[0] + nums[1] + nums[2]
for i in range(n - 2):
left, right = i + 1, n - 1
while left < right:
sum_val = nums[i] + nums[left] + nums[right]
if abs(sum_val - target) < abs(closest - target):
closest = sum_val
if sum_val < target:
left += 1
elif sum_val > target:
right -= 1
else:
return sum_val
return closest
public class Solution {
public int ThreeSumClosest(int[] nums, int target) {
Array.Sort(nums);
int n = nums.Length;
int closest = nums[0] + nums[1] + nums[2];
for (int i = 0; i < n - 2; i++) {
int left = i + 1, right = n - 1;
while (left < right) {
int sum = nums[i] + nums[left] + nums[right];
if (Math.Abs(sum - target) < Math.Abs(closest - target)) {
closest = sum;
}
if (sum < target) {
left++;
} else if (sum > target) {
right--;
} else {
return sum;
}
}
}
return closest;
}
}
var threeSumClosest = function(nums, target) {
nums.sort((a, b) => a - b);
const n = nums.length;
let closest = nums[0] + nums[1] + nums[2];
for (let i = 0; i < n - 2; i++) {
let left = i + 1, right = n - 1;
while (left < right) {
const sum = nums[i] + nums[left] + nums[right];
if (Math.abs(sum - target) < Math.abs(closest - target)) {
closest = sum;
}
if (sum < target) {
left++;
} else if (sum > target) {
right--;
} else {
return sum;
}
}
}
return closest;
};
复杂度分析
| 复杂度类型 | 复杂度 | 说明 |
|---|---|---|
| 时间复杂度 | O(n²) | 外层循环 O(n),内层双指针 O(n) |
| 空间复杂度 | O(1) | 只使用常数级额外空间(不计排序空间) |
相关题目
. 3Sum (Medium)
. 3Sum Smaller (Medium)