16. 3Sum Closest**
https://leetcode.com/problems/3sum-closest/description/
题目描述
Given an array nums
of n integers and an integer target, find three integers in nums
such that the sum is closest to target. Return the sum of the three integers. You may assume that each input would have exactly one solution.
Example:
For example, given array S = {-1 2 1 -4}
, and target = 1
.
The sum that is closest to the target is 2
. (-1 + 2 + 1 = 2)
.
给定一个整数数组 S, 在其中找到 3 个整数使得它们的和接近一个给定的 target. 返回这 3 个数的和.
解题思路
思路: 类似于 15. 3Sum. 为了得到最接近 target
的值, 要计算使 std::abs(target - sum)
最小的那个 sum
. 为了得到这些 sum
, 和 15. 3Sum 一样, 首先对数组进行排序, 然后固定 nums[i]
, 再对后面的内容进行 2Sum
.
C++ 实现 1
代码中使用 res
来记录每次找到的最小的三元组 a + b + c
之和.
class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
if (nums.size() < 3)
return accumulate(nums.begin(), nums.end(), 0);
int res = nums[0] + nums[1] + nums[nums.size() - 1];
std::sort(nums.begin(), nums.end());
for (int i = 0; i < nums.size() - 2; ++i) {
int lo = i + 1, hi = nums.size() - 1;
while (lo < hi) {
int sum = nums[lo] + nums[hi] + nums[i];
if (sum == target)
return sum;
if (sum > target)
hi --;
else {
lo ++;
}
if (std::abs(target - sum) < std::abs(target - res))
res = sum;
}
}
return res;
}
};
推荐阅读
再看一个 leetcode 上解释非常详细的:
A n^2 Solution, Can we do better ?
int threeSumClosest(vector<int> &num, int target) {
vector<int> v(num.begin(), num.end()); // I didn't wanted to disturb original array.
int n = 0;
int ans = 0;
int sum;
sort(v.begin(), v.end());
// If less then 3 elements then return their sum
while (v.size() <= 3) {
return accumulate(v.begin(), v.end(), 0);
}
n = v.size();
/* v[0] v[1] v[2] ... v[i] .... v[j] ... v[k] ... v[n-2] v[n-1]
* v[i] <= v[j] <= v[k] always, because we sorted our array.
* Now, for each number, v[i] : we look for pairs v[j] & v[k] such that
* absolute value of (target - (v[i] + v[j] + v[k]) is minimised.
* if the sum of the triplet is greater then the target it implies
* we need to reduce our sum, so we do K = K - 1, that is we reduce
* our sum by taking a smaller number.
* Simillarly if sum of the triplet is less then the target then we
* increase out sum by taking a larger number, i.e. J = J + 1.
*/
ans = v[0] + v[1] + v[2];
for (int i = 0; i < n-2; i++) {
int j = i + 1;
int k = n - 1;
while (j < k) {
sum = v[i] + v[j] + v[k];
if (abs(target - ans) > abs(target - sum)) {
ans = sum;
if (ans == target) return ans;
}
(sum > target) ? k-- : j++;
}
}
return ans;
}