题目
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:
Given array nums = [-1, 2, 1, -4], and target = 1.
The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).
解法一
暴力穷举,时间复杂度维O(N^3)
class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
sort(nums.begin(), nums.end());
int distance =abs( target - nums[0] - nums[1] - nums[2]);
int result = nums[0] + nums[1] + nums[2];
for(int i = 0; i < nums.size() - 2; i++)
for(int j = i+1; j < nums.size() - 1; j++)
for (int k = j + 1; k < nums.size() ; k++){
if (distance > abs(target - nums[i] - nums[j] - nums[k])) {
distance = abs(target - nums[i] - nums[j] - nums[k]);
result = nums[i] + nums[j] + nums[k];
}
}
return result;
}
};
解法二
基于方法一的优化
通过分析,我们可以想到一种时间复杂度为O(n^2)的解法:假设数组中有len个元素,首先我们将数组中的元素按照从小到大的顺序进行排序。其次,看最终取出的三个数中的第一个数,若数组长度为n,那么有n种取法。假设取的第一个数是A[i],那么第二三两个数从A[i+1]~A[len]中取出。找到“第一个数为A[i]固定,后两个数在A[i]后面元素中取。并且三数之和离target最近的情况。”这时,我们用两个指针j,k分别指向A[i+1]和A[len],如果此时三数之和A[i]+A[j]+A[k]<target,说明三数之和小了,我们将j后移一格;反之,若和大于target,则将k前移一格;直到j和k相遇为止。在这期间,保留与target最近的三数之和。一旦发现有“和等于target的情况”,立即输出即可。
由于取的第一个数可以是A[0],A[1],A[2],……,A[len-1],所以需要重复以上步骤n次。
为什么第一个数取了A[i]之后,第二三两个数只能在A[i+1]~A[len]中取呢? 因为这样可以避免重复。假设第二个数取了A[i-2],那么这样情况势必会包含在第一个数取A[i-2]的情况中。因为取出的三个数之间是没有顺序关系的。
class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
sort(nums.begin(), nums.end());
int distance = abs(target - nums[0] - nums[1] - nums[2]);
int result = nums[0] + nums[1] + nums[2];
int nowResult = nums[0] + nums[1] + nums[2];
for (int i = 0; i < nums.size() - 2; i++) {
int j = i + 1;
int k = nums.size() - 1;
nowResult = nums[i] + nums[j] + nums[k];
while (j < k) {
if (nowResult < target)
j++;
else
k--;
if (distance > abs(target - nowResult)) {
result = nowResult;
distance = abs(target - nowResult);
}
nowResult = nums[i] + nums[j] + nums[k];
}
}
return result;
}
};