3Sum Closest

来源:互联网 发布:软件管理360 编辑:程序博客网 时间:2024/05/16 06:53

题目

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;    }}