LeetCode 16. 最接近的三数之和(3Sum Closest)解题详解

LeetCode 16. 最接近的三数之和(3Sum Closest)解题详解

难度:中等

相关标签:数组、双指针、排序

相关企业:各大科技公司面试常见题目


题目描述

给你一个长度为 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)。

提示

  • 3 <= nums.length <= 1000
  • -1000 <= nums[i] <= 1000
  • -10^4 <= target <= 10^4

解题思路

这道题要求我们找到三个数的和最接近目标值 target。为了解决这个问题,我们可以采用以下步骤:

  1. 排序数组:先将数组 nums 进行排序。这有助于我们利用双指针技术高效地寻找三元组。

  2. 遍历数组:固定第一个数,然后使用双指针在剩余的数组中寻找另外两个数,使得三数之和最接近 target

  3. 双指针

    • 初始化两个指针,一个指向当前固定数之后的第一个数(left),另一个指向数组的末尾(right)。
    • 计算当前三数之和 a = nums[i] + nums[left] + nums[right]
    • 如果 a 比当前最接近的和更接近 target,则更新结果。
    • 根据 atarget 的关系,移动 leftright 指针:
      • 如果 a < target,移动 left 指针向右,以增加和。
      • 如果 a > target,移动 right 指针向左,以减少和。
      • 如果 a == target,直接返回 a,因为这是最接近的和。
  4. 记录最小差值:在遍历过程中,持续记录与 target 差值最小的三数之和。

代码实现

以下是基于上述思路的 Python 代码实现:

from typing import List
from collections import Counter

class Solution:
    def threeSumClosest(self, nums: List[int], target: int) -> int:
        # 排序数组
        nums.sort()
        n = len(nums)
        # 初始化最接近的和为无穷大
        ans = float('inf')
        # 遍历数组,固定第一个数
        for i in range(n - 2):
            # 初始化双指针
            left = i + 1
            right = n - 1
            while left < right:
                # 计算当前三数之和
                a = nums[i] + nums[left] + nums[right]
                # 如果当前和比之前的更接近目标,更新答案
                if abs(a - target) < abs(ans - target):
                    ans = a
                # 根据当前和与目标的关系,移动指针
                if a < target:
                    left += 1
                elif a > target:
                    right -= 1
                else:
                    # 如果和等于目标,直接返回
                    return a
        return ans

代码解析

1. 排序数组

nums.sort()
n = len(nums)

首先对数组进行排序,这样可以方便地使用双指针技术。排序的时间复杂度是 O(n log n)

2. 初始化最接近的和

ans = float('inf')

使用 ans 来记录当前最接近 target 的三数之和,初始值设为无穷大。

3. 遍历数组并固定第一个数

for i in range(n - 2):
    left = i + 1
    right = n - 1

通过遍历数组的每个元素,固定第一个数 nums[i],然后在剩余的数组中使用双指针 leftright 寻找另外两个数。

4. 使用双指针寻找最接近的三数之和

while left < right:
    a = nums[i] + nums[left] + nums[right]
    if abs(a - target) < abs(ans - target):
        ans = a
    if a < target:
        left += 1
    elif a > target:
        right -= 1
    else:
        return a
  • 计算当前三数之和 a
  • 如果 atarget 的差值比之前的差值更小,更新 ans
  • 根据 atarget 的大小关系,移动 leftright 指针:
    • a < target:说明当前和偏小,需要增加和,因此移动 left 向右。
    • a > target:说明当前和偏大,需要减少和,因此移动 right 向左。
    • a == target:直接返回 a,因为已经是最接近的和。

5. 返回结果

return ans

遍历完成后,返回最接近的三数之和 ans

示例分析

示例 1

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

步骤

  1. 排序后 nums = [-4, -1, 1, 2]
  2. 固定第一个数 -4,使用双指针在 [-1, 1, 2] 中寻找:
    • 当前和 -4 + (-1) + 2 = -3,差值为 4
    • -3 < 1,移动左指针。
    • 当前和 -4 + 1 + 2 = -1,差值为 2
    • -1 < 1,移动左指针。
  3. 固定第一个数 -1,使用双指针在 [1, 2] 中寻找:
    • 当前和 -1 + 1 + 2 = 2,差值为 1
    • 2 > 1,移动右指针,结束。
  4. 最终最接近的和为 2

示例 2

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

步骤

  1. 排序后 nums = [0, 0, 0]
  2. 固定第一个数 0,使用双指针在 [0, 0] 中寻找:
    • 当前和 0 + 0 + 0 = 0,差值为 1
    • 0 < 1,移动左指针,结束。
  3. 最终最接近的和为 0

性能分析

  • 时间复杂度O(n^2)

    • 排序需要 O(n log n)
    • 外层循环遍历 n 个元素,内层双指针遍历最多 n 个元素。
    • 总体时间复杂度为 O(n^2)
  • 空间复杂度O(1)(忽略输入和输出)

    • 除了排序所需的空间外,没有使用额外的空间。

总结

这道题目采用了排序和双指针的经典技巧,通过固定一个元素,并在剩余部分使用双指针寻找最接近的三数之和。关键在于理解如何利用排序和双指针高效地缩小搜索范围,并持续更新最接近的结果。

这种方法不仅适用于本题,也在很多类似的数组问题中有广泛应用,如 3Sum 等。

如果你对这道题还有疑问,欢迎在评论区讨论!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值