最接近的三数之和

中等题
在这里插入图片描述
类似“三数之和”,同样都是三个循环优化成两个循环,思路也非常类似,一道双指针的练习题。此类题为了降低复杂度肯定要先进行排序,因为没有经过排序的数组所包含的信息比较少。除去一层循环,剩下两个指针就很明确了。
经过排序的数组有以下特征:保持两个指针不变(我们这里至少能确定第一个指针不变),第三个指针右移,三数之和必然增加;第三个指针左移,三数之和必然减小。利用这个单调性,就可以把二、三层循环合并。
分类讨论如下:

  1. a一定,当a+b+c>target: 只能减小b或c,否则就会离target越来越远。
  2. a一定,当a+b+c<target: 只能增大b或c。

综上,二层循环设置头尾两个指针。当a+b+c>target,减小c;当a+b+c<target,增大b,直到b=c。同时,对数组中出现的相同元素可以排除,因为题目规定只有一组解。

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

class Solution {
public:
    int threeSumClosest(vector<int>& nums, int target) {
        sort(nums.begin(),nums.end());
        int len = nums.size();
        int best = 1e7;
        for(int first=0; first<len-2; first++){
            if(first > 0 && nums[first] == nums[first-1]) continue; //可能出现重复,只选第一个
            int third = len-1; //写在这里是因为third和second是同一级的,也就是每个first循环应该找到一个<second,third>对
            int second=first+1;
            while(third>second){
                int sum = nums[first]+nums[second]+nums[third];
                if(sum == target) return target; //相同就直接退出了,相当于剪枝
                if(abs(sum-target)<abs(best-target)){
                    //更新
                    best = sum;
                }
                if(sum>target){
                    int third0 = third-1;
                    while(second<third0 && nums[third] == nums[third0]){
                        //排除重复
                        --third0;
                    }
                    third=third0;
                }
                else{
                    int second0 = second+1;
                    while(second0<third && nums[second0] == nums[second]){
                        ++second0;
                    }
                    second=second0;
                }
            }
        }
        return best;
    }
};

int main(){
    Solution st;
    vector<int> vt = {-1,2,1,-4};

    cout<<st.threeSumClosest(vt,3)<<endl;

    return 0;
}

总结:这是双指针的一道基本题,在确定了双指针的策略后,最重要的应该是找到数学关系。在本题中,target是已知量,先确定a,则a也变为已知量,表达式变成b+c与target-a最接近。接着分析b+c与target-a的关系,再确定其中的一个量b或c,这就需要具体问题具体分析。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值