Leetcode16. 3Sum Closest-最接近的三数和(99.88%时间应该是最优解了)

题目

题目链接

思路

对数组升序排序,外层从前到后遍历(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)
    可能每一次判断,都要将当前的三数和加入候选列表,因此与时间复杂度在同一量级
  1. 改进版 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%
在这里插入图片描述

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值