1. 题目
给你一个长度为 n n n 的整数数组 n u m s nums nums 和 一个目标值 t a r g e t target target。请你从 n u m s nums nums 中选出三个整数,使它们的和与 t a r g e t target target 最接近。
返回这三个数的和。
假定每组输入只存在恰好一个解。
示例 1:
输入:
n
u
m
s
=
[
−
1
,
2
,
1
,
−
4
]
,
t
a
r
g
e
t
=
1
nums = [-1,2,1,-4], target = 1
nums=[−1,2,1,−4],target=1
输出:2
解释:与
t
a
r
g
e
t
target
target 最接近的和是 2 (-1 + 2 + 1 = 2) 。
示例 2:
输入:
n
u
m
s
=
[
0
,
0
,
0
]
,
t
a
r
g
e
t
=
1
nums = [0,0,0], target = 1
nums=[0,0,0],target=1
输出:0
提示:
- 3 < = n u m s . l e n g t h < = 1000 3 <= nums.length <= 1000 3<=nums.length<=1000
- − 1000 < = n u m s [ i ] < = 1000 -1000 <= nums[i] <= 1000 −1000<=nums[i]<=1000
- − 1 0 4 < = t a r g e t < = 1 0 4 -10^4 <= target <= 10^4 −104<=target<=104
2. 思路及代码实现(Python)
2.1 排序 + 双指针
类似于前文,求三数之和的《LeetCode_15_中等_三数之和》,可以考虑l对数组排序后用双指针进行快速搜索。而本题不是求和为固定值的三数,转为求最接近目标值 t a r g e t target target 的三元组,即三数之和与目标值的差值的绝对值最小。
同样是先排序(升序),当固定了第一个值时,如果三个数之和大于等于 t a r g e t target target,此时增加第二个值只会增大三数之和,离目标值越来越远,因此当达到了这个边界时,不会有固定第一个、第三个值之后的其他组合,此时移动第二个值无效,因此出现该情况移动第三个值的索引;若三数之和达到另一个边界,小于目标值,此时固定第一第二个值时,移动第三个值不会比当前的组合更好,因此可以移动第二个值。
时间复杂度显然为 O ( N 2 ) O(N^2) O(N2),空间复杂度为 O ( N ) O(N) O(N),相比于题15的三数之和,区别在于需要根据三树之和与目标值的差值来更新最优的和,而逻辑基本一致。
class Solution:
def threeSumClosest(self, nums: List[int], target: int) -> int:
nums.sort()
n = len(nums)
best = 10**7
# 根据差值的绝对值来更新答案
def update(cur):
nonlocal best
if abs(cur - target) < abs(best - target):
best = cur
# 枚举 a
for i in range(n):
# 保证和上一次枚举的元素不相等
if i > 0 and nums[i] == nums[i - 1]:
continue
# 使用双指针枚举 b 和 c
j, k = i + 1, n - 1
while j < k:
s = nums[i] + nums[j] + nums[k]
# 如果和为 target 直接返回答案
if s == target:
return target
update(s)
if s > target:
# 如果和大于 target,移动 c 对应的指针
k0 = k - 1
# 移动到下一个不相等的元素
while j < k0 and nums[k0] == nums[k]:
k0 -= 1
k = k0
else:
# 如果和小于 target,移动 b 对应的指针
j0 = j + 1
# 移动到下一个不相等的元素
while j0 < k and nums[j0] == nums[j]:
j0 += 1
j = j0
return best
执行用时:578 ms
消耗内存:16.52 MB
参考来源:力扣官方题解