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

};

提交后的结果如下:

LeetCode刷题笔记(3Sum Closest)

方法二(优化方法一)

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

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

 提交后的结果如下:

LeetCode刷题笔记(3Sum Closest)

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