最接近的三数之和
题目
给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。
例如,给定数组 nums = [-1,2,1,-4], 和 target = 1.
与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2).
解题思路
- 数组排序 + 双指针;
- 对数组进行排序,初始化返回值
res
为float('inf')
正无穷,用以比较赋值; - 遍历数组,根据下面的步骤查找最接近的值:
- 先固定一个值
nums[i]
,定义双指针L
和R
,分别指向固定值的下一位,以及最末尾的值; - 考虑边界问题:
- 取包括固定值后续三位数之和(因为数组已排序,
nums[i] + nums[L]+nums[L+1]
)为当前最小值 this_min,若是 this_min 比 target 大,表示后续的数值无论怎么组合,值都会比 this_min 大,所以这里直接比较 this_min 和 res 跟 target 的差值的绝对值,res 取较小的值,结束循环; - 取固定值与末尾最后的两位数值之和为当下的最大值 this_max,若是 this_max 比 target 小,表示后续有更大可能接近 target 的值。这里也比较 this_max 和 res 跟 target 的差值绝对值,res 取较小值,然后跳过。
- 取包括固定值后续三位数之和(因为数组已排序,
- 不存在边界问题时,在双指针之间进行遍历,计算固定值与双指针指向的值之和 three_sum;
- 当 three_sum 等于 target 时,直接返回 target;
- 当 three_sum 不等于 target 时,比较 three_sum 和 res 与 target 的差值绝对值,res 取较小值
- 当 three_sum 小于 target 时,左指针往右边移动,寻找更接近的值,注意去重;
- 当 three_sum 大于 target 时,右指针往左移动,寻找更接近的值,注意去重;
- 循环过程取固定值时,考虑避免取到重复的固定值。
- 时间复杂度:O(n2)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
实现结果
题外话
本题主要需要考虑的点在于边界问题的处理。这一块的处理,能够很大程度上快速给出结果值。
以上就是本篇的主要内容。
欢迎关注微信公众号《书所集录》