最接近的三数之和
原题地址:最接近的三数之和
题目描述:
给你一个长度为 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
,这里要返回三数相加最接近target
的和。
那对于这道题目,类似的,我们仍然可以考虑用排序+双指针的方法。
具体做法如下:
1.先对原数组进行一次排序。
2.然后一层for循环固定一个元素。
3.循环体内部使用双指针在固定元素之和的部分中找剩下符合题意的两个元素。
4.第一个指针指向剩余部分的第一个元素,第二个指针指向数组最后一个元素。
5.求三个元素之和,若等于0,直接返回(因为不可能存在更接近的了);剩下情况,计算当前和与历史和之间差与差的绝对值,若差大于0,第二个指针左移;若差小于0,第一个指针右移。若差的绝对值小于0,则将当前和赋给历史和。
6.当两个指针相遇,继续第一层for循环。
7.最后返回历史和。
代码如下:
class Solution:
def threeSumClosest(self, nums: List[int], target: int) -> int:
n = len(nums)
nums.sort()
res = nums[0] + nums[1] + nums[2] # 用数组元素初始化,一般是起始元素
for i in range(n - 2): # 找三个元素,先固定一个,然后从剩下的部分里面找两个元素,取值范围可不就是0~n-3嘛
if i > 0 and nums[i] == nums[i-1]: # 去重
continue
# 双指针
left = i+1 # 第一个指针位置为i向右移动一位
right = n-1 # 第二个指针位置为数组末位
while (left < right):
if nums[i] + nums[left] + nums[right] == target:
return target
if abs(target - nums[i] - nums[left] - nums[right]) < abs(target - res):
res = nums[i] + nums[left] + nums[right]
if nums[i] + nums[left] + nums[right] < target:
# 当三元素之和小于target时,需要将第一个指针向右移动一位
left += 1
if nums[i] + nums[left] + nums[right] > target:
# 当三元素之和大于target时,需要将第二个指针向左移动一位
right -= 1
return res
总结
时间复杂度:
乍一看使用了一个for循环体,两个while循环体,好像复杂度是 O ( n 3 ) O(n^3) O(n3),然而,仔细观察可以看到,其实第二个while循环体(最后的两个while循环看作一个)只是帮助跳过一些重复的元素而已,因此,总的时间复杂度还是 O ( n 2 ) O(n^2) O(n2)。
空间复杂度:
不确定,取决于排序算法的内部实现过程。