最接近的三数之和

给你一个长度为 n 的整数数组 nums 和 一个目标值 target。请你从 nums 中选出三个整数,使它们的和与 target 最接近。

返回这三个数的和。

假定每组输入只存在恰好一个解。

示例 1:

输入:nums = [-1,2,1,-4], target = 1

输出:2

解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。

示例 2: 

输入:nums = [0,0,0], target = 1

输出:0

提示:

  • 3 <= nums.length <= 1000
  • -1000 <= nums[i] <= 1000
  • -104 <= target <= 104

 

1、这题要我们取出三个数,求其和然后找到与target最接近的那一个组合

 

2、其实最明显最直接的方法就是用三次循环暴力求解,也就是找到所有方案然后再和target做出比较。这种思路虽然清晰,但是付出的代价确实巨大的,正所谓“当我们想要得到一些东西,就会失去一些东西”。失去的就是运行的时间与运行的内存,由于一共嵌套了三次循环,所以时间复杂度应该是O(n^3)

3、当我们舍弃了暴力求解后就该去想想能不能减少循环嵌套的次数,如果我们能将循环变成两次,也就是固定一层循环。让我们引出一个新思路:排序+双指针

当我们用sort()函数将容器排序后,我们可以根据三个数之和与target的距离(想想改用什么表示数轴上两个点的距离,当然是二者之差的绝对值咯,用到了abs()函数),如果三个数之和比target要大了,我们就让我们的end指针向左移动,也就是让end指针指向更小的数,相反的,如果三个数之和比target要小了,我们就让我们的start的指针向右移动,也就是让start指针指向更大的数,要是相等那可就太好了,直接返回就是了。如此一来,我们至少可以保证他们两个的距离更近。

我们所假想的情况有两个前提:

1、容器必须顺序排列,必须必须必须!不然就不能保证找到的是我们想要的顺序了

2、start指针要比end指针靠前,这或许就是我们的循环条件

当上述完成后,我们不能忘记我们固定的那个循环,也就是那个不动的数,当start=end的时候,也就是上述过程完成,我们需要让不变的数开始转变,然后再让他走过每一个数,所以我们事实上只需要两个循环,一个外层的不动数的循环移动,另一个是内层双指针的向中间移动

是不是比暴力求解少了很多步骤呢,实际上这个方法的时间复杂度只有O(n^2),在n很大的时候,这个方法的优势就会有所展现……

以下是C++的求解代码

class Solution {
public:
    int threeSumClosest(vector<int>& nums, int target) {
        sort(nums.begin(),nums.end());
        int closestSum=nums[0]+nums[1]+nums[2];
        for(int i=0;i<nums.size()-2;++i){
            int start=i+1,end=nums.size()-1;
            while(start<end)
            {
                if(abs(nums[i]+nums[start]+nums[end]-target)<abs(closestSum-target))
                {
                    closestSum=nums[i]+nums[start]+nums[end];
                }
                if(nums[i]+nums[start]+nums[end]>target)
                --end;
                else if(nums[i]+nums[start]+nums[end]<target)
                ++start;
                else 
                return nums[i]+nums[start]+nums[end];
            }
        }
        return closestSum;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

听风逝夜al

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值