题目描述
给你一个长度为 n
的整数数组 nums
和 一个目标值 target
。请你从 nums
中选出三个整数,使它们的和与 target
最接近。
返回这三个数的和。
假定每组输入只存在恰好一个解。
样例
输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2)。
输入:nums = [0,0,0], target = 1
输出:0
限制
3 <= nums.length <= 1000
-1000 <= nums[i] <= 1000
-10^4 <= target <= 10^4
算法
(两重枚举) $O(n^2)$
算法思想类似于3Sum。
- 首先将
nums
数组排序,然后固定一重循环枚举起始位置i
。 - 然后初始
l = i + 1
,r = n - 1
;如果发现nums[i] + nums[l] + nums[r] == target
,则可以直接返回target
; - 若发现
nums[i] + nums[l] + nums[r] < target
,则l++
;否则r--
; - 直到
l>=r
停止,继续向后增加初始位置i
。
时间复杂度
- 排序的时间复杂度为 $O(n \log n)$。
- 共有 $n$ 个起始位置,然后每次循环 $l$ 和 $r$ 的时间复杂度为 $O(n)$。
- 故总时间复杂度为 $O(n^2)$。
空间复杂度
- 仅需要常数的额外空间。
C++ 代码:
class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
int ans = nums[0] + nums[1] + nums[2];
sort(nums.begin(), nums.end());
for (int i = 0; i < nums.size(); i++) {
int l = i + 1, r = nums.size() - 1;
while (l < r) {
if (abs(nums[i] + nums[l] + nums[r] - target) < abs(ans - target))
ans = nums[i] + nums[l] + nums[r];
if (nums[i] + nums[l] + nums[r] == target)
return target;
else if (nums[i] + nums[l] + nums[r] < target)
l++;
else
r--;
}
}
return ans;
}
};
其实最后一个方法还可以利用排序后数组的性质做一个优化。第一个优化是对于每个i都先算一下 target是否大于nums[i]+nums[n-1]+nums[n-2],如果是的话,就没有必要再接下去算了,直接更新ans=nums[i]+nums[n-1]+nums[n-2];第二个优化是对于每个i ,计算3*nums[i]是否大于target,如果是的话,直接将nums[i]+nums[i+1]+nums[i+2]和ans比,看哪个离target更近,直接返回。
如果nums没有3个数怎么办?
加特判,但是题目constrain写了至少3个