题目
Given an array S of n integers, find three integers in S such that the sum is closest to a given number, target. Return the sum of the three integers. You may assume that each input would have exactly one solution.
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).
思路一
先遍历所有的可能的三元组,再计算和最接近target的三元组和。
class Solution {
public:
int threeSumClosest(vector<int> &num, int target) {
// Start typing your C/C++ solution below
// DO NOT write int main() function
vector<vector<int>> result;
if(num.size()<3)
return 0;
sort(num.begin(),num.end());
vector<int> myvec;
mythree(result,myvec,num,0,0);
int res = 0;
int min = 0;
for(int i=0;i<result.size();i++)
{
int tmp = result[i][0]+result[i][1]+result[i][2];
if(i==0)
{
min = abs(tmp-target);
res = tmp;
}
if(abs(tmp-target)<min)
{
min = abs(tmp-target);
res = tmp;
}
}
return res;
}
void mythree(vector<vector<int>> &result, vector<int> &vec, vector<int> &num, int cur, int sum)
{
if(vec.size()==3)
{
result.push_back(vec);
return ;
}
if(vec.size()>3 || cur==num.size())
return ;
for(int i=cur;i<num.size();i++)
{
if(i>cur && num[i]==num[i-1])
continue;
vec.push_back(num[i]);
mythree(result,vec,num,i+1,sum+num[i]);
vec.pop_back();
}
}
};
上述代码的缺点是 需要实现存储所有的三元组,所以 空间复杂度比较高。在测试大数据是,会出现 Run Status: Output Limit Exceeded
其实上述代码没必要存储所有的三元组。于是有了思路二。
思路二
class Solution {
public:
int threeSumClosest(vector<int> &num, int target) {
// Start typing your C/C++ solution below
// DO NOT write int main() function
if(num.size()<3)
return 0;
sort(num.begin(),num.end());
vector<int> myvec;
int min = abs(num[0]+num[1]+num[2]-target);
int res = num[0]+num[1]+num[2];
mythree(myvec,num,0,min,res,target);
return res;
}
void mythree(vector<int> &vec, vector<int> &num, int cur, int &min, int &res, int target)
{
if(vec.size()==3)
{
int tmp = vec[0]+vec[1]+vec[2];
if(abs(tmp-target)<min)
{
min = abs(tmp-target);
res = tmp;
}
return ;
}
if(vec.size()>3 || cur==num.size())
return ;
for(int i=cur;i<num.size();i++)
{
if(i>cur && num[i]==num[i-1])
continue;
vec.push_back(num[i]);
mythree(vec,num,i+1,min,res,target);
vec.pop_back();
}
}
};
该方法可以通过小数据集,但是对于大数据集,又出现了 Run Status: Time Limit Exceeded
所以这种 基于全遍历的方法 是会超时的。
同时我们考虑到:target=5,当前 min =3,即
(1)若tmp<target ,则tmp=2 , 我们知道往后遍历时,只要tmp<target,则min是不断减小的;
(2)若tmp>target ,则tmp=8 , 我们知道往后遍历时,只要tmp>target,则min是不断增加的;
所以可以剪枝部分不符合条件的遍历。
class Solution {
public:
int threeSumClosest(vector<int> &num, int target) {
// Start typing your C/C++ solution below
// DO NOT write int main() function
if(num.size()<3)
return 0;
sort(num.begin(),num.end());
vector<int> myvec;
int min = abs(num[0]+num[1]+num[2]-target);
int res = num[0]+num[1]+num[2];
mythree(myvec,num,0,min,res,target);
return res;
}
void mythree(vector<int> &vec, vector<int> &num, int cur, int &min, int &res, int target)
{
if(vec.size()==3)
{
int tmp = vec[0]+vec[1]+vec[2];
if(abs(tmp-target)<min)
{
min = abs(tmp-target);
res = tmp;
}
return ;
}
if(vec.size()>0 && vecSum(vec)-target>min)
return ;
if(vec.size()>3 || cur==num.size())
return ;
mythree(vec,num,cur+1,min,res,target);
vec.push_back(num[cur]);
mythree(vec,num,cur+1,min,res,target);
vec.pop_back();
}
int vecSum(vector<int> &myvec)
{
int sum = 0;
for(int i=0;i<myvec.size();i++)
sum+=myvec[i];
return sum;
}
};
其中 if(vec.size()>0 && vecSum(vec)-target>min) return ;
就是剪枝语句。
但是好像对于大数据,还是Run Status: Time Limit Exceeded
分析:虽然加入了剪枝,时间复杂度好像还是 O(N3) 的。
思路三
以第 i 个元素为中间点,分别向左、向右遍历,left 、 right 和 i 记录 当前三元组。
根据值与target的关系更新left和right。
class Solution {
public:
int threeSumClosest(vector<int> &num, int target) {
// Start typing your C/C++ solution below
// DO NOT write int main() function
if(num.size()<3)
return 0;
sort(num.begin(),num.end());
int res = num[0]+num[1]+num[2];
int min = abs(target-res);
for(int i=1;i<num.size()-1;i++)
{
int left = i-1;
int right = i+1;
while(left>=0 && right<num.size())
{
int tmp = num[left]+num[i]+num[right];
if(tmp==target)
return tmp;
else if(tmp<target)
{
if(target-tmp<=min)
{
min = target-tmp;
res = tmp;
}
right++;
}
else
{
if(tmp-target<=min)
{
min = tmp-target;
res = tmp;
}
left--;
}
}
}
return res;
}
};
时间复杂度是O(N2) 的。
最新 java
public class Solution {
public int threeSumClosest(int[] nums, int target) {
if(nums == null || nums.length < 3){
return 0;
}
Arrays.sort(nums);
int result = nums[0]+nums[1]+nums[2];
int min = Math.abs(result-target);
// dfs(result, list, nums, 0, 0);
for(int i=0; i<nums.length-2; i++){
// //avoid duplicate solutions
if (i == 0 || nums[i] > nums[i-1]) {
int start = i + 1;
int end = nums.length - 1;
while(start < end){
int sum = nums[i] + nums[start] + nums[end];
//case 1
if (sum == target) {
return sum;
//case 2
} else if (sum < target) {
if(target - sum < min){
min = target - sum;
result = sum;
}
start++;
//avoid duplicate solutions
while (start < end && nums[start] == nums[start - 1])
start++;
//case 3
} else {
if(sum - target < min){
min = sum - target;
result = sum;
}
end--;
//avoid duplicate solutions
while (start < end && nums[end] == nums[end + 1])
end--;
}
}
}
}
return result;
}
}