LeetCode 16. 3Sum Closest
题目要求:给出一个整型数组nums和一个整数target,要求从nums中找出3个整数a,b,c使得它们的和最接近target。
题目给出的框架如下所示:
class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
}
};
解题思路
这道题和之前的3Sum极为相似,原理参考上一篇文章LeetCode 15. 3Sum。
只是条件有所改变从原来的nums[i]+nums[j]+nums[k]与0的比较,变成了nums[i]+nums[j]+nums[k]与target的比较。
但需要注意的是:3Sum的结果可以为空,本题的结果一定不为空,因此不能加上循环条件nums[k] < target/3。
具体做法如下:
- 固定一个数k,在它后面找出两个数i=k+1和j=length-1,i和j不断向中间移动,使得nums[i]+nums[j]+nums[k]的值尽可能接近target,用minus记录target与nums[i]+nums[j]+nums[k]的差值,即:minus = target - nums[i] - nums[j] - nums[k];
- 为了使nums[i]+nums[j]+nums[k]的值尽可能接近target,因此,需要分为以下3种情况考虑:
若nums[i]+nums[j]+nums[k] == target,则直接返回nums[i]+nums[j]+nums[k];
若nums[i]+nums[j]+nums[k] < target,则为了使结果靠近target,应当使得i向右移动,nums[i]增大后,三者之和也相应的增大;
若nums[i]+nums[j]+nums[k] > target,则为了使结果靠近target,应当使得j向左移动,nums[j]减小后,三者之和也相应的减小; - 为了剔除重复的情况,i和j在移动的时候碰到相同的元素应当继续向前移动,但是k不能,如果k碰到相同的就移动的话,可能会造成没有结果的情况,如nums={1,1,1,1}和targt=0。
代码实现
代码实现如下:
class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
sort(nums.begin(), nums.end());
int minus = INT_MAX;
for (int k = 0; k < nums.size() - 2; ++k) {
if (k > 0 && nums[k] == nums[k - 1])
continue;
int i = k + 1, j = nums.size() - 1;
while (i < j) {
if (abs(target - nums[i] - nums[j] - nums[k]) < abs(minus)) {
minus = target - nums[i] - nums[j] - nums[k];
}
if (nums[i] + nums[j] + nums[k] == target)
return target;
if (nums[i] + nums[j] + nums[k] < target) {
while (++i < j && nums[i] == nums[i - 1])
; // 跳过重复元素
}
if (nums[i] + nums[j] + nums[k] > target) {
while (i < --j && nums[j] == nums[j + 1])
; // 跳过重复元素
}
}
}
return target - minus;
}
};