LeetCode 第16题:最接近的三数之和

LeetCode 第16题:最接近的三数之和

题目描述

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

返回这三个数的和。

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

难度

中等

题目链接

https://leetcode.cn/problems/3sum-closest/

示例

示例 1:

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

示例 2:

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

提示

  • 3 <= nums.length <= 1000
  • -1000 <= nums[i] <= 1000
  • -104 <= target <= 104

解题思路

方法:排序 + 双指针

这道题是三数之和的变体,主要区别在于需要找最接近目标值的和,而不是恰好等于目标值的和。

关键点:

  1. 先对数组排序,便于使用双指针
  2. 固定第一个数,使用双指针寻找另外两个数
  3. 记录当前和与目标值的差的绝对值,保存最小差值对应的和
  4. 根据当前和与目标值的大小关系移动指针

具体步骤:

  1. 对数组进行排序
  2. 初始化一个变量记录最接近的和
  3. 遍历数组,固定第一个数nums[i]:
    • 使用双指针在剩余部分寻找最接近的和
    • 根据当前和与target的比较决定指针移动方向
  4. 更新最接近的和

时间复杂度:O(n²)
空间复杂度:O(1)

代码实现

C# 实现

public class Solution {
    public int ThreeSumClosest(int[] nums, int target) {
        // 排序
        Array.Sort(nums);
        int n = nums.Length;
        int closestSum = nums[0] + nums[1] + nums[2];
      
        // 固定第一个数
        for (int i = 0; i < n - 2; i++) {
            int left = i + 1;
            int right = n - 1;
          
            while (left < right) {
                int currentSum = nums[i] + nums[left] + nums[right];
              
                // 如果找到完全相等的和,直接返回
                if (currentSum == target) {
                    return currentSum;
                }
              
                // 更新最接近的和
                if (Math.Abs(currentSum - target) < Math.Abs(closestSum - target)) {
                    closestSum = currentSum;
                }
              
                // 根据和与目标值的关系移动指针
                if (currentSum < target) {
                    left++;
                } else {
                    right--;
                }
            }
        }
      
        return closestSum;
    }
}

优化版本(添加剪枝)

public class Solution {
    public int ThreeSumClosest(int[] nums, int target) {
        Array.Sort(nums);
        int n = nums.Length;
        int closestSum = nums[0] + nums[1] + nums[2];
      
        // 如果最小的三个数和大于target,直接返回
        if (closestSum >= target) {
            return closestSum;
        }
      
        // 如果最大的三个数和小于target,直接返回
        int largestSum = nums[n-1] + nums[n-2] + nums[n-3];
        if (largestSum <= target) {
            return largestSum;
        }
      
        for (int i = 0; i < n - 2; i++) {
            // 计算当前位置可能的最小三数之和
            int minSum = nums[i] + nums[i + 1] + nums[i + 2];
          
            // 如果最小和已经大于target,后面的组合只会更大
            if (minSum > target) {
                return Math.Abs(minSum - target) < Math.Abs(closestSum - target) ? 
                       minSum : closestSum;
            }
          
            int left = i + 1;
            int right = n - 1;
          
            while (left < right) {
                int currentSum = nums[i] + nums[left] + nums[right];
              
                if (currentSum == target) {
                    return currentSum;
                }
              
                if (Math.Abs(currentSum - target) < Math.Abs(closestSum - target)) {
                    closestSum = currentSum;
                }
              
                if (currentSum < target) {
                    left++;
                } else {
                    right--;
                }
            }
        }
      
        return closestSum;
    }
}

代码详解

基本版本:

  1. 排序的作用:
    • 便于使用双指针
    • 可以有序地寻找最接近的和
  2. 双指针移动策略:
    • 当前和小于target时左指针右移
    • 当前和大于target时右指针左移
  3. 更新最接近和:
    • 比较当前和与目标值的差的绝对值
    • 保存差值最小的和

优化版本:

  1. 边界条件处理:
    • 检查最小三数之和
    • 检查最大三数之和
  2. 剪枝优化:
    • 计算当前位置可能的最值
    • 根据与target的关系提前返回或跳过

执行结果

基本版本:

  • 执行用时:84 ms
  • 内存消耗:38.5 MB

优化版本:

  • 执行用时:76 ms
  • 内存消耗:38.3 MB

总结与反思

  1. 这道题的关键点:
    • 理解与三数之和的区别
    • 高效地更新最接近的和
    • 合理移动双指针
  2. 优化思路:
    • 添加边界条件判断
    • 使用剪枝减少不必要的遍历
    • 提前返回确定的结果
  3. 注意事项:
    • 初始化最接近和的选择
    • 处理相等情况可以提前返回
    • 考虑整数溢出的可能

相关题目

posted @   旧厂街小江  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示