leetcode-最接近的三数之和

 题目来自LeetCode,链接:3sum-closest。具体描述为:给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。

 示例:

例如,给定数组 nums = [-1,2,1,-4], 和 target = 1.
与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2).

 这跟前一道题/前一篇博客的三数之和解法很类似,可以套用那道题的解法。首先对数组排序,然后对于当前的数,其右边的数组成一个子数组(而且是升序的),给定左指针为子数组最左,右指针为子数组最右,左指针对应左数,右指针对应右数。利用一个变量记录最小误差。则:

  • 计算三数之和与target的误差,若此误差的绝对值小于最小误差的绝对值,则更新最小误差为当前误差(可正可负);
  • 如果三数之和=target,则直接返回target就行了;
  • 如果三数之和<target,说明增大左数可能使得三数之和更靠近target,所以左指针右移;
  • 否则即三数之和>target,说明减少右数可能使得三数之和更靠近target,所以右指针左移。

最后当前面的流程进行到左指针遇到/超过右指针就结束了,此时要把当前数右移到不与当前数相同位置,同样是为了避免重复。

 最后需要返回的结果就是target+最小误差。

 可以看到这种方法的时间复杂度同样为 O ( n 2 ) O(n^{2}) O(n2),空间复杂度为 O ( 1 ) O(1) O(1)

 JAVA版代码如下:

class Solution {
    public int threeSumClosest(int[] nums, int target) {
        int numsLen = nums.length;
        Arrays.sort(nums);
        int i = 0;
        int minError = Integer.MAX_VALUE;
        while (i < numsLen - 2) {
            int left = i + 1;
            int right = numsLen - 1;
            while (left < right) {
                int error = nums[i] + nums[left] + nums[right] - target;
                if (Math.abs(error) < Math.abs(minError)) {
                    minError = error;
                }
                if (error == 0) {
                    return target;
                }
                else if (error < 0) {
                    ++left;
                }
                else {
                    --right;
                }
            }
            ++i;
            while (i < numsLen -2 && nums[i] == nums[i - 1]) {
                ++i;
            }
        }
        return target + minError;
    }
}

 提交结果如下:


 Python版代码如下:

class Solution:
    def threeSumClosest(self, nums: List[int], target: int) -> int:
        nums.sort()                                         #先升序排序
        length = len(nums)
        result = []
        i = 0
        minError = float('inf')
        while i < length - 2:                               #只遍历到倒数第3个数
            left = i + 1
            right = length - 1
            now_num = nums[i]
            while left < right:                             #当左指针和右指针相遇就结束一轮循环
                left_num = nums[left]
                right_num = nums[right]
                error = now_num + left_num + right_num - target
                if abs(error) < abs(minError):              #更新最小的误差绝对值
                    minError = error
                if error == 0:                              #三个数的和为target
                    return target
                elif error < 0:                             #当三个数的和小于target时,左指针右移
                    left += 1
                else:                                       #当三个数的和大于target时,右指针左移
                    right -= 1
            i += 1
            while i < length - 2 and nums[i] == now_num:    #第一个数移动到不与之前一样为止
                i += 1
        return minError + target

 提交结果如下:


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值