最接近的三数之和

题意

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

返回这三个数的和。假定每组输入只存在恰好一个解。

难度

中等

示例

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

输出:2

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

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

输出:0

分析

既然是最接近的三数之和,那显然我们就可以采用三数之和的解思路,先排序,然后固定一个数,再用双指针去找另外两个数。

三数之和的时候和为 0,这里的和为最接近 target 的一个数,那其实解法就真的差不多了。

class Solution {
    public int threeSumClosest(int[] nums, int target) {
        // 对数组进行排序
        Arrays.sort(nums);
        // 数组长度
        int n = nums.length;
        // 初始化最接近的和为前三个元素的和
        int closestSum = nums[0] + nums[1] + nums[2];

        // 遍历数组,除了最后两个元素(因为我们需要三个数)
        for (int i = 0; i < n - 2; i++) {
            // 双指针初始化,left 指向当前元素之后的元素,right 指向数组最后一个元素
            int left = i + 1, right = n - 1;
            while (left < right) {
                // 计算当前三个数的和
                int sum = nums[i] + nums[left] + nums[right];
                // 如果当前和与目标值的差的绝对值小于最接近和与目标值的差的绝对值
                if (Math.abs(target - sum) < Math.abs(target - closestSum)) {
                    // 更新最接近的和
                    closestSum = sum;
                }
                // 根据和与目标值的比较,移动指针
                if (sum > target) {
                    right--; // 和大于目标值,移动右指针向左
                } else if (sum < target) {
                    left++; // 和小于目标值,移动左指针向右
                } else {
                    return sum; // 如果和等于目标值,直接返回当前和
                }
            }
        }
        // 返回找到的最接近的和
        return closestSum;
    }
}

我们来简单分析下:

①、排序:首先对数组进行排序。双指针的前提就是数组要有序,这样才方便移动指针。

②、初始化最接近 target 的和:假设数组中前三个数的和就是最进阶 target 的值。

③、遍历数组:遍历数组,固定一个数 nums[i]。

  1. 双指针查找:在 nums[i] 后面的数组部分设置双指针,一个是 i 的下一位 i + 1,另一个是数组的末尾 n - 1。
  2. 移动这两个指针,寻找和最接近 target 的三数组合。
  3. 更新最接近的和:如果找到更接近 target 的和,就更新这个最接近的和。比如说,初始的和为 10,target 为 2,那如果我们找到了一个和为 5 的三数组合,那这个和就比 10 更接近 2,所以我们就更新这个最接近的和为 5。

④、终止条件:如果某次三数之和等于 target,直接返回 target,因为不能更接近了。

这里需要注意的两个点,一个是如何判断最接近的和,我们用了 Math.abs() 方法,这个方法是取绝对值的意思,比如说 Math.abs(-1) 的结果就是 1,Math.abs(1) 的结果还是 1。

当一个数与目标数 target 的差越小,那么这个数也就越接近 target。相信大家都能理解,5-3=2 < 10-3=7,那么 5 就比 10 更接近 3。

if (Math.abs(target - sum) < Math.abs(target - closestSum)) {

// 更新最接近的和

closestSum = sum;

}

另外一个点是移动左指针还是右指针,当 sum 大于 target,说明 sum 太大了,需要减小 sum,那么就移动右指针,反之,如果 sum 小于 target,说明 sum 太小了,需要增大 sum,那么就移动左指针。

if (sum > target) {

right--; // 和大于目标值,移动右指针向左

} else if (sum < target) {

left++; // 和小于目标值,移动左指针向右

} else {

return sum; // 如果和等于目标值,直接返回当前和

}

当输入是 nums = [-1,2,1,-4], target = 1 的时候,就需要移动左指针,因为 sum 太小了,需要增大 sum。

好,来看一下题解效率,还不错。

总结

那刷题其实就是这样,学会举一反三,遇到不同的题型,尽量去找到和它相似的题型,能不能按照之前的解题思路快速把这道题解出来,解出来后再想办法去优化。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值