Leetcode16. 3Sum Closest
题目
思路
对数组升序排序,外层从前到后遍历(i),选定nums[i]后,
里层循环对i后面的数组求最接近target-nums[i]的两个数,
先判断边界情况(选定nums[i]后,在后面的数组里能找到的最大和与最小和),可以省去一部分不必要的判断,
再用两个指针在后面数组求和,一个从左到右,一个从右到左,相遇时退出里层循环
复杂度
- 时间复杂度
O
(
N
2
)
\mathcal{O}(N^2)
O(N2)
两层循环 - 空间复杂度
1.原始版 O ( N 2 ) \mathcal{O}(N^2) O(N2)
可能每一次判断,都要将当前的三数和加入候选列表,因此与时间复杂度在同一量级
- 改进版
O
(
1
)
\mathcal{O}(1)
O(1)
去掉候选列表,每次只保留最接近的候选即可
空间高占( O ( N 2 ) \mathcal{O}(N^2) O(N2))
参考这里
class Solution(object):
def threeSumClosest(self, nums, target):
nums.sort()
length = len(nums)
closest = []
for i in range(length-2):
left = i+1
right = length-1
# 先计算nums[i]对应最小的三数和,如果最小都大于target则直接添加
if nums[i] + nums[left] + nums[left+1] > target:
closest.append(nums[i] + nums[left] + nums[left+1])
# 计算nums[i]对应最大的三数和,如果最大都小于target则直接添加
elif nums[i] + nums[right] + nums[right-1] < target:
closest.append(nums[i] + nums[right] + nums[right-1])
# 否则按照原来方法逐个计算每个三数和
else:
while left < right:
closest.append(nums[i] + nums[left] + nums[right])
if closest[-1] < target:
left += 1
elif closest[-1] > target:
right -= 1
else:
return target
# closest按照离target最近的条件排序,返回最接近target的值
closest.sort(key=lambda x: abs(x-target))
return closest[0]
beats 99.68%:
空间改进( O ( 1 ) \mathcal{O}(1) O(1))
可以看到空间占用主要来自closest候选列表,那能不能每次只保留一个值呢,改进如下
class Solution(object):
def threeSumClosest(self, nums, target):
nums.sort()
length = len(nums)
closest = 0
min_diff = float("inf")
for i in range(length-2):
left = i+1
right = length-1
# 先计算nums[i]对应最小的三数和,如果最小都大于target则直接添加
min_sum = nums[i] + nums[left] + nums[left+1]
max_sum = nums[i] + nums[right] + nums[right-1]
cur_diff = abs(min_sum - target)
max_diff = abs(max_sum - target)
if min_sum > target:
if cur_diff < min_diff:
min_diff = cur_diff
closest = min_sum
# 计算nums[i]对应最大的三数和,如果最大都小于target则直接添加
elif max_sum < target:
if max_diff < min_diff:
min_diff = max_diff
closest = max_sum
# 否则按照原来方法逐个计算每个三数和
else:
while left < right:
cur_sum = nums[i] + nums[left] + nums[right]
cur_diff = abs(cur_sum - target)
if cur_diff < min_diff:
min_diff = cur_diff
closest = cur_sum
if cur_sum < target:
left += 1
elif cur_sum > target:
right -= 1
else:
return target
return closest
99.88%/89.23%