16. 最接近的三数之和

16. 最接近的三数之和

题目描述

给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。

示例
输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。
提示:
  • 3 ≤ n u m s . l e n g t h ≤ 1 0 3 3 \le nums.length \le 10^3 3nums.length103
  • − 1 0 3 ≤ n u m s [ i ] ≤ 1 0 3 -10^3 \le nums[i] \le 10^3 103nums[i]103
  • − 1 0 4 ≤ t a r g e t ≤ 1 0 4 -10^4 \le target \le 10^4 104target104

题解:

排序+双指针。

此题在 15. 三数之和 的基础上稍微变形了一下,核心思想仍然没变。

最简单粗暴的方法是:三重循环枚举所有可能的三元组,找到离 target 最近的作为答案,这样的时间复杂度为 O ( n 3 ) O(n^3) O(n3)

我们可以考虑枚举第一个元素 nums[i] ,对于剩下的两个元素 nums[j]nums[k] ,我们希望它们的和最接近 target - nums[i] 。而如果在原来的数组上枚举 nums[j]nums[k] 的话,因为它们是无序的,所以需要二重循环枚举,但是如果是有序(升序)的话,那么我们就可以只需要一重循环即可。

具体操作流程:

  • 对数组进行升序排序

  • 枚举第一个元素 nums[i]

  • j = i + 1, k = n - 1

  • 分情况讨论:

    1. 如果 nums[i] + nums[j] + nums[k] > target ,可以理解为此时三元组的和离 target 较远(太大了),而减小 nums[k] 的值可能会减小差距,所以 --k

    2. 如果 nums[i] + nums[j] + nums[k] < target ,可以理解为此时三元组的和离 target 较远(太小了),而增加 nums[j] 的值可能会减小差距,所以 ++j

    3. 如果 nums[i] + nums[j] + nums[k]== target,此时直接返回 target 即可

    4. 记得更新差值

一个小优化:nums[i] == nums[i - 1] 时可以跳过该元素,避免重复同样的操作。

时间复杂度: O ( n 2 ) O(n^2) O(n2)

额外空间复杂度: O ( 1 ) O(1) O(1)

代码:

class Solution {
public:
    int threeSumClosest(vector<int>& nums, int target) {
        int n = nums.size();
        sort(nums.begin(), nums.end());
        int gap = INT_MAX;
        int ret = -1, t, ans;
        for ( int i = 0; i < n; ++i ) {
            if ( i && nums[i] == nums[i - 1] ) continue;
            for ( int j = i + 1, k = n - 1; j < k; ) {
                t = nums[i] + nums[j] + nums[k];
                if ( t == target ) return t;
                ans = abs( t - target );
                if ( ans < gap ) {
                    gap = ans;
                    ret = t;
                }
                if ( t > target ) --k;
                else ++j;
            }
        }
        return ret;
    }
};
/*
时间:4ms,击败:100.00%
内存:9.5MB,击败:99.96%
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值