16. 最接近的三数之和

题目描述

给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。

示例:
输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。
  • 3 <= nums.length <= 10^3
  • -10^3 <= nums[i] <= 10^3
  • -10^4 <= target <= 10^4

解题思路

这道题和15题非常类似,15题问的是三数和为0,而这里是寻找三个数和与目标最接近的情况。首先还是会想到暴力解法,时间复杂度达到了O(n^3)。

1. 枚举法
int threeSumClosest(vector<int>& nums, int target) {
        int i=0,j=0,k,min=1000000,ap=0,ans;//min存放差最小值,ans输出最后的答案
        vector<int> temp;
        sort(nums.begin(),nums.end());
        for(i=0;i<nums.size();i++){
            for(j=i+1;j<nums.size();j++){
                k=nums.size()-1;
                while(j<k)    
                {
                    ap=abs(nums[i]+nums[j]+nums[k]-target);
                    if(ap<min)
                    {min=ap;
                    ans=nums[i]+nums[j]+nums[k];}
                    k--;
                }
            }
        }
        return ans;
    }

这里的写法有一些借鉴了15题,没有写三重循环,但是其实k也是参与循环了。这个代码刚好可以通过,但是时间耗时较长,需要进行优化。

2. 排序+双指针

与15题一样,先进行排序,然后使用双指针。但是使用的时候需要注意一下,这里的判断条件略有不同:

如果a+b+c≥target,那么就将k向左移动一个位置
如果a+b+c<target,那么就将j向右移动一个位置

这样可以保证和越来越接近target。求每次的值并取最小:

int threeSumClosest(vector<int>& nums, int target) {
        int i=0,j=0,k,min=1000000,ap=0,ans;
        vector<int> temp;
        sort(nums.begin(),nums.end());
        for(i=0;i<nums.size();i++){
            k=nums.size()-1;
            for(j=i+1;j<nums.size();j++){
                while(j<k)    
                {
                    ap=abs(nums[i]+nums[j]+nums[k]-target);
                    if(ap<min)
                    {min=ap;
                    ans=nums[i]+nums[j]+nums[k];}
                    if(nums[i]+nums[j]+nums[k]<target){//增加了这个的判断,提高效率
                        j++;
                    }
                    else k--;
                }
            }
        }
        return ans;
    }

留下评论