LeetCode 最接近的三数之和

最接近的三数之和


题目来源:https://leetcode-cn.com/problems/3sum-closest

题目


给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。

例如,给定数组 nums = [-1,2,1,-4], 和 target = 1.

与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2).

解题思路


  1. 数组排序 + 双指针;
  2. 对数组进行排序,初始化返回值 resfloat('inf') 正无穷,用以比较赋值;
  3. 遍历数组,根据下面的步骤查找最接近的值:
    1. 先固定一个值 nums[i],定义双指针 LR,分别指向固定值的下一位,以及最末尾的值;
    2. 考虑边界问题:
      1. 取包括固定值后续三位数之和(因为数组已排序,nums[i] + nums[L]+nums[L+1])为当前最小值 this_min,若是 this_min 比 target 大,表示后续的数值无论怎么组合,值都会比 this_min 大,所以这里直接比较 this_min 和 res 跟 target 的差值的绝对值,res 取较小的值,结束循环;
      2. 取固定值与末尾最后的两位数值之和为当下的最大值 this_max,若是 this_max 比 target 小,表示后续有更大可能接近 target 的值。这里也比较 this_max 和 res 跟 target 的差值绝对值,res 取较小值,然后跳过。
    3. 不存在边界问题时,在双指针之间进行遍历,计算固定值与双指针指向的值之和 three_sum;
    4. 当 three_sum 等于 target 时,直接返回 target;
    5. 当 three_sum 不等于 target 时,比较 three_sum 和 res 与 target 的差值绝对值,res 取较小值
    6. 当 three_sum 小于 target 时,左指针往右边移动,寻找更接近的值,注意去重;
    7. 当 three_sum 大于 target 时,右指针往左移动,寻找更接近的值,注意去重;
    8. 循环过程取固定值时,考虑避免取到重复的固定值。
    9. 时间复杂度: O ( n 2 ) O(n^2) O(n2)

代码实现


class Solution:
    def threeSumClosest(self, nums: List[int], target: int) -> int:
        # 先对数组进行排序
        nums.sort()
        nl= len(nums)
        # 将返回值初始化为正无穷
        res = float('inf')

        for i in range(nl-2):
            # 去重
            if i > 0 and nums[i] == nums[i-1]:
                continue
            # 定义双指针
            # 左边指针指向固定值下一位
            # 右边指针指向末尾
            L, R = i+1, nl-1

            # 处理边界的问题
            this_min = nums[i] + nums[L] + nums[L+1]
            # 数组已经排序,将连续三位数字作为当下最小值
            # 若是当下最小的值比 target 还大,后面的数值与 target 的差值会越来越大
            # 比较当前最小值和返回值各自与 target 差值的大小,赋值之后跳出循环
            if this_min > target:
                if (this_min - target) < abs(res - target):
                    res = this_min
                break
            
            # 将当前值与最末尾两位数值之和作为当前的最大值
            # 若是当下最大值比 target 小,这里可以确定后续可能还有更接近的值
            # 所以比较当下最大值和返回值与 target 差值大小,赋值后,直接跳过
            this_max = nums[i] + nums[R-1] + nums[R]
            if this_max < target:
                if (target - this_max) < abs(res - target):
                    res = this_max
                continue
            
            # 不满足上面的条件时
            # 在两指针的区间进行遍历
            while L < R:
                # 计算固定值与双指针对应值三者之和
                three_sum = nums[i] + nums[L] + nums[R]
                # 若结果等于 target,直接返回 target
                if three_sum == target:
                    return target
                # 比较 three_num 和 res 分别与 target 的差值,res 取较小值
                if abs(three_sum - target) < abs(res - target):
                    res = three_sum
                # three_num 小于 target 时,左指针往右移动,寻找更接近的值
                if three_sum < target:
                    L += 1
                    # 去重
                    while L < R and nums[L] == nums[L-1]:
                        L += 1
                # three_num 大于 target 时,右指针往左移动,寻找更接近的值
                else:
                    R -= 1
                    # 去重
                    while L < R and nums[R] == nums[R+1]:
                        R -= 1
        
        return res
        

实现结果


实现结果

题外话


本题主要需要考虑的点在于边界问题的处理。这一块的处理,能够很大程度上快速给出结果值。


以上就是本篇的主要内容。


欢迎关注微信公众号《书所集录》

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值