Medium

题目描述

给你一个长度为 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 <= 500
  • -1000 <= nums[i] <= 1000
  • -10^4 <= target <= 10^4

解题思路

这道题是经典的三指针问题,可以通过排序 + 双指针的方式高效求解。

基本思路:

  1. 首先对数组进行排序,这样可以使用双指针技巧
  2. 固定第一个数,然后用双指针在剩余数组中寻找最接近目标值的两数之和
  3. 维护一个全局的最接近值,不断更新

具体步骤:

  1. 对数组排序
  2. 遍历数组,固定第一个元素 nums[i]
  3. 设置左指针 left = i + 1,右指针 right = n - 1
  4. 计算三数之和 sum = nums[i] + nums[left] + nums[right]
  5. 如果当前和比之前记录的更接近目标值,则更新结果
  6. 根据和与目标值的关系调整指针:
    • 如果 sum < target,说明和太小,左指针右移
    • 如果 sum > target,说明和太大,右指针左移
    • 如果 sum == target,直接返回(找到最接近的解)

时间复杂度优化: 可以通过跳过重复元素来避免不必要的计算。

这种方法比暴力枚举所有三元组的 O(n³) 解法更加高效。

代码实现

class Solution {
public:
    int threeSumClosest(vector<int>& nums, int target) {
        sort(nums.begin(), nums.end());
        int n = nums.size();
        int closest = nums[0] + nums[1] + nums[2];
        
        for (int i = 0; i < n - 2; i++) {
            int left = i + 1, right = n - 1;
            
            while (left < right) {
                int sum = nums[i] + nums[left] + nums[right];
                
                if (abs(sum - target) < abs(closest - target)) {
                    closest = sum;
                }
                
                if (sum < target) {
                    left++;
                } else if (sum > target) {
                    right--;
                } else {
                    return sum;
                }
            }
        }
        
        return closest;
    }
};
class Solution:
    def threeSumClosest(self, nums: List[int], target: int) -> int:
        nums.sort()
        n = len(nums)
        closest = nums[0] + nums[1] + nums[2]
        
        for i in range(n - 2):
            left, right = i + 1, n - 1
            
            while left < right:
                sum_val = nums[i] + nums[left] + nums[right]
                
                if abs(sum_val - target) < abs(closest - target):
                    closest = sum_val
                
                if sum_val < target:
                    left += 1
                elif sum_val > target:
                    right -= 1
                else:
                    return sum_val
        
        return closest
public class Solution {
    public int ThreeSumClosest(int[] nums, int target) {
        Array.Sort(nums);
        int n = nums.Length;
        int closest = nums[0] + nums[1] + nums[2];
        
        for (int i = 0; i < n - 2; i++) {
            int left = i + 1, right = n - 1;
            
            while (left < right) {
                int sum = nums[i] + nums[left] + nums[right];
                
                if (Math.Abs(sum - target) < Math.Abs(closest - target)) {
                    closest = sum;
                }
                
                if (sum < target) {
                    left++;
                } else if (sum > target) {
                    right--;
                } else {
                    return sum;
                }
            }
        }
        
        return closest;
    }
}
var threeSumClosest = function(nums, target) {
    nums.sort((a, b) => a - b);
    const n = nums.length;
    let closest = nums[0] + nums[1] + nums[2];
    
    for (let i = 0; i < n - 2; i++) {
        let left = i + 1, right = n - 1;
        
        while (left < right) {
            const sum = nums[i] + nums[left] + nums[right];
            
            if (Math.abs(sum - target) < Math.abs(closest - target)) {
                closest = sum;
            }
            
            if (sum < target) {
                left++;
            } else if (sum > target) {
                right--;
            } else {
                return sum;
            }
        }
    }
    
    return closest;
};

复杂度分析

复杂度类型复杂度说明
时间复杂度O(n²)外层循环 O(n),内层双指针 O(n)
空间复杂度O(1)只使用常数级额外空间(不计排序空间)

相关题目