Leecode#16刷题之最接近的三数之和

题目

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

返回这三个数的和。

假定每组输入只存在恰好一个解。

示例 1:

复制代码
输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2)。

示例 2:

复制代码
输入:nums = [0,0,0], target = 1
输出:0
解释:与 target 最接近的和是 0(0 + 0 + 0 = 0)。

Java语言

java 复制代码
class Solution {
    public int threeSumClosest(int[] nums, int target) {
        Arrays.sort(nums);
        int closest = nums[0] + nums[1] + nums[2];  // 初始用前三个数的和

        for (int i = 0; i < nums.length - 2; i++) {
            int left = i + 1, right = nums.length - 1;

            while (left < right) {
                int sum = nums[i] + nums[left] + nums[right];
                int diff = sum - target;

                // 比 closest 更接近 target 就更新
                if (Math.abs(diff) < Math.abs(closest - target)) {
                    closest = sum;
                }

                if (diff < 0) {
                    left++;       // 和太小,右移 left
                } else if (diff > 0) {
                    right--;      // 和太大,左移 right
                } else {
                    return sum;   // diff == 0,完美匹配,直接返回
                }
            }
        }

        return closest;
    }
}

核心思路: 排序 + 双指针。和上一题(三数之和)一样的框架,但不再要求和恰好为 0,而是记录最接近 target 的和。


逐行说明:

java 复制代码
Arrays.sort(nums);

int closest = nums[0] + nums[1] + nums[2];

先排序(双指针的前提)。closest 初始取前三个数的和,作为初始最接近值。

java 复制代码
for (int i = 0; i < nums.length - 2; i++) {

遍历第一个数,到 length - 2 停止。

java 复制代码
int left = i + 1, right = nums.length - 1;

while (left < right) {

int sum = nums[i] + nums[left] + nums[right];

int diff = sum - target;

双指针,计算三数之和与 target 的差值 diff

java 复制代码
if (Math.abs(diff) < Math.abs(closest - target)) {

closest = sum;

}

如果当前和与 target 的差距比之前记录的更小,就更新 closestMath.abs() 取绝对值。

java 复制代码
if (diff < 0) {

left++;

} else if (diff > 0) {

right--;

} else {

return sum;

}
  • diff < 0:和太小,left 右移让和变大
  • diff > 0:和太大,right 左移让和变小
  • diff == 0:和等于 target,不可能更接近了,直接返回
java 复制代码
return closest;

返回最接近的和。


与三数之和的区别:

特性 三数之和 (15题) 最接近三数之和 (16题)
目标 和恰好等于 0 和最接近 target
去重 需要 不需要(只返回一个和)
记录 所有满足条件的三元组 始终记录最接近的和

示例 1 演示: nums = [-1,2,1,-4] → 排序后 [-4,-1,1,2], target = 1

i numsi left right sum diff closest 操作
0 -4 1 3 -4+(-1)+2=-3 -4 -3 → abs=3 最初始 closest=-3, abs(-4)>abs(-4) 不更新, diff<0 left++
0 -4 2 3 -4+1+2=-1 -2 -1 → abs=2 abs(-2)
0 -4 3 3 left>=right 退出
1 -1 2 3 -1+1+2=2 1 2 → abs=1 abs(1)0 right--
1 -1 2 2 left>=right 退出

最终返回 2

时间复杂度 O(n²),空间复杂度 O(1)(不计排序)。

python语言

python 复制代码
class Solution(object):
    def threeSumClosest(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        nums.sort()
        closest = nums[0] + nums[1] + nums[2]

        for i in range(len(nums) - 2):
            left, right = i + 1, len(nums) - 1

            while left < right:
                total = nums[i] + nums[left] + nums[right]
                diff = total - target

                if abs(diff) < abs(closest - target):
                    closest = total

                if diff < 0:
                    left += 1
                elif diff > 0:
                    right -= 1
                else:
                    return total

        return closest

逻辑与 Java 版完全一致,逐行说明:

python 复制代码
nums.sort()

closest = nums[0] + nums[1] + nums[2]

排序,初始最接近值取前三个数的和。nums.sort() 原地排序,对应 Java 的 Arrays.sort(nums)

python 复制代码
for i in range(len(nums) - 2):

left, right = i + 1, len(nums) - 1

遍历第一个数,双指针分别从 i+1 和末尾开始。left, right = i + 1, len(nums) - 1 一行同时赋值两个变量。

python 复制代码
while left < right:

total = nums[i] + nums[left] + nums[right]

diff = total - target

计算三数之和与 target 的差值。

python 复制代码
if abs(diff) < abs(closest - target):

closest = total

当前和更接近 target 就更新。abs() 取绝对值,对应 Java 的 Math.abs()

python 复制代码
if diff < 0:

left += 1

elif diff > 0:

right -= 1

else:

return total
  • diff < 0:和太小,left 右移
  • diff > 0:和太大,right 左移
  • diff == 0:完美匹配,直接返回
python 复制代码
return closest

返回最接近的和。


与 Java 版的关键区别:

特性 Java Python
排序 Arrays.sort(nums) nums.sort()
列表长度 nums.length len(nums)
绝对值 Math.abs(x) abs(x)
双变量赋值 int left = a, right = b; left, right = a, b
自增/自减 left++ / right-- left += 1 / right -= 1

时间复杂度 O(n²),空间复杂度 O(1)(不计排序)。

相关推荐
倒头就睡的小比特17 小时前
算法竞赛C++常用的STL
c++·算法
小羊没烦恼!18 小时前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
猎头南楼19 小时前
知识社区推荐系统实践:新用户冷启动与长短期兴趣建模的挑战 资深推荐算法工程师
人工智能·深度学习·算法·机器学习
m0_5474866619 小时前
《数据结构教程》全套 PPT课件2026
数据结构
旖旎夜光20 小时前
力控面试题 01.01: 判定字符是否唯一(位运算) —— 题解
c++·学习·算法·leetcode·力控
wzdark20 小时前
大规模并行计算中的负载均衡算法研究4
算法
Because_of_Her120 小时前
并查集-听课笔记
笔记·算法·并查集
码流子20 小时前
高速公路安全监测实践:碰撞监测预警+物联网底座,从感知到处置的闭环
大数据·人工智能·物联网·算法·架构
another heaven20 小时前
【算法/C++ MD5算法能否逆解码?原理、C++实现与同类哈希算法对比】
c++·算法·哈希算法
wzdark21 小时前
从算法设计模式看编程思维的抽象能力4
算法