LeetCode刷题笔记(3Sum Closest)

今天又刷了一道题,感觉对对撞指针这种方法又有了新的认识,下面就来总结一下吧!

Given an array nums of n integers and an integer target, find three integers in nums such that the sum is closest to target. Return the sum of the three integers. You may assume that each input would have exactly one solution.

Example:

Given array nums = [-1, 2, 1, -4], and target = 1.

The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).

题意分析: 

给定一个包含n个整数的nums数组(数组没有特殊指明,应该可以为空集),请寻找哪个三元组合之和为target或者最接近target,并返回该组合的和。注:不需要以组合集的方式返回,只需要返回满足条件的组合的和。

解答如下:

方法一(对撞“指针”法)

先对向量进行排序,然后用for循环固定向量中最左边第一个数nums[0],再将i=1时,nums[i]+nums[l]+nums[r]记录成res,res-target的绝对值记录成error(error用于衡量当下nums[i]+nums[l]+nums[r]之和是否更接近target,所以我们只需要找到最小error对应的三元组合并返回它们的和即可),紧接着用对撞“指针”的方式,从排除了固定数的向量的两端进行扫描,不断找寻最小的error。最后通过for循环依次固定每个元素,执行相同操作,直到倒数第三个数即可寻得最小error对应三元组合的和。

注:①对撞指针中,两个指针不能同时相向移动,如果需要去重则需要两个while循环分别控制左右指针。②在指针移动时,要充分结合有序数组这一特点,原则:和偏大则右指针--,和偏小左指针++。

class Solution{
public:
    int threeSumClosest( vector<int>& nums, int target){
        int res = 0;
        int error = 0;
        int len = nums.size();
        sort(nums.begin(), nums.end());
        for (int i = 0; i < len - 2; i++) {
            int l = i + 1;
            int r = len - 1;
            if( i == 0)
               { res= nums[i] + nums[l] + nums[r];
                error = abs(res - target);}
            //下面这个while用于寻找最小的error
            while (l < r) {
                if (abs( nums[i] + nums[l] + nums[r] - target) < error ){
                    res = nums[i] + nums[l] + nums[r];
                    error = abs(res - target);
                    }
                //下面这个if用于控制两端指针的变化
                if (nums[i] + nums[l] + nums[r] == target) return nums[i] + nums[l] + nums[r];
                else if (nums[i] + nums[l] + nums[r] > target) r--;
                else l++;
                }

        }
        return res;
    }

};

提交后的结果如下:

方法二(优化方法一)

多用一些中间变量,省去冗余代码,使程序变得更通俗易懂。

class Solution{
public:
    int threeSumClosest( vector<int>& nums, int target){
        int res = nums[0] + nums[1] + nums[2];
        int error =  abs(res - target);
        sort(nums.begin(), nums.end());
        for (int i = 0; i < nums.size() - 2; i++) {
            int l = i + 1;
            int r = nums.size() - 1; 
            while (l < r) {              //寻找最小error
                int sum = nums[i] + nums[l] + nums[r];
                int newerror = abs( sum - target);
                if (newerror < error ){   
                        error = newerror;
                        res = sum;
                    }
                if (sum > target) r--;   //控制两端指针变化,这里无须判断sum == target,因为被newerror = 0包含了
                else l++;
                }
        }
        return res;
    }
};

 提交后的结果如下:

日积月累,与君共进,增增小结,未完待续。     

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值