算法题:16. 最接近的三数之和(题目+思路+代码+注释)时空击败98%、91%用户(双指针思路)

在这里插入图片描述

题目

给定一个包括 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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/3sum-closest
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

  • 穷举方法就是三层循环全部试一遍,既然是个算法题,那肯定不能这样简单粗暴呀
  • 问题拆分:既然要找三个数最近的,我们可以固定第一个数,拿target 减去第一个数,然后把求三个数的问题变为求后面两个数最近的值,再去和历史记录里最近的比较就可以找出最近的三个数了。
  • 找后面两个数的时候如果说要遍历暴力穷举还是跟之前的三层循环一样的简单粗暴了,那么我们如何去减少不必要的比较和运算呢?既然要靠近,那么我可以先对数组排序,这样我就可以用双指针取一个小的一个大的,判断,大了的话就是要减小值,也就是右指针往左移动就可以减小值了,小了的时候左指针往右边移动就增大,这样就能更快速的找出三数之和最近的和。
    在这里插入图片描述

代码

public int threeSumClosest(int[] nums, int target) {
        //排序
        Arrays.sort(nums);
        int len = nums.length;
        int closest = nums[0] + nums[1] + nums[2];
        int gap = Math.abs(target - closest);
        for (int i = 0,maxLeft = nums.length-2,t,g; i < maxLeft;i++){
            int sum = target - nums[i];
            for (int j = i+1,k = nums.length-1;j < k;){
                t = nums[j] + nums[k];
                if (t == sum ){
                    //相等的情况
                    return target;
                }
                if (t < sum){
                    //左指针右移到不相同的值
                    while (j+1 < len && nums[j] == nums[j+1]) {
                        j++;
                    }
                    j++;
                }else {
                    //右指针左移到不相同的值
                    while (k - 1 > j && nums[k] == nums[k-1]){
                        k--;
                    }
                    k--;
                }
                //记录最相近的
                g = Math.abs(target - t - nums[i]);
                if (g < gap){
                    gap = g;
                    closest = t + nums[i];
                }
            }
        }
        return closest;
    }
posted @ 2021-07-27 10:29  HumorChen99  阅读(30)  评论(0编辑  收藏  举报  来源