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)(不计排序)。

相关推荐
Yfhonier21 分钟前
岛屿数量(DFS)
算法·深度优先
橘子汽水16822 分钟前
Leetcode15:三数之和
java·数据结构·算法
黄金龙PLUS25 分钟前
ASCON置换算法的优缺点
算法·网络安全·密码学·哈希算法·同态加密
邪修king31 分钟前
Re:Linux 系统篇(十六):进程篇(五):O (1) 调度算法深度解析 —— 优先级数组、位图优化与活跃 / 过期双队列
linux·运维·算法
Yfhonier1 小时前
6440. 极大连通图个数(DFS)
数据结构·算法·深度优先
Rnan-prince1 小时前
从 Bitmap、BloomFilter到 Count-Min Sketch:三个数据结构,一条“用误差换空间“的演进线
数据结构·sketch·bitmap
玖玥拾1 小时前
LeetCode 1 两数之和
算法·leetcode·职场和发展
Cccp.1231 小时前
【leetcode】(一)认识复杂度和简单排序算法
算法·排序算法