73 最接近的三数之和(3Sum Closest)

1 题目

题目:最接近的三数之和(3Sum Closest)
描述:给一个包含 n 个整数的数组 S, 找到和与给定整数 target 最接近的三元组,返回这三个数的和。只需要返回三元组之和,无需返回三元组本身

lintcode题号——59,难度——medium

样例1:

输入:
numbers = [2,7,11,15]
target = 3
输出:20
解释:2+7+11=20

样例2:

输入:
numbers = [-1,2,1,-4]
target = 1
输出:2
解释:-1+2+1=2

2 解决方案

2.1 思路

  考虑循环遍历数组,固定其中一个数,再在剩下的子数组中找到和最接近目标值的两数即可。在子数组中找到最接近目标值的两数,可以使用对向双指针的方式,两个指针分别从头尾开始向中间走,若指针指向的两个值的和大于目标值,则将右指针往左一步;若两个值的和小于或等于目标值,则右指针往左一步,在循环过程中进行打擂台,比较当前的差值和记录的最小值,直到数组遍历结束。

2.2 时间复杂度

  排序的时间复杂度O(n * log n),外层循环的时间复杂度为O(n),twoSumClosest的时间复杂度为O(n),总时间复杂度为O(n^2)。

2.3 空间复杂度

  空间复杂度为O(1)。

3 源码

细节:

  1. 需要先对数组排序。
  2. 使用循环固定其中一个数,再在剩下的子数组中寻找最接近新目标值的两个数。
  3. 使用打擂台的方式,寻找最接近的值。

C++版本:

扫描二维码关注公众号,回复: 14637057 查看本文章
/**
* @param numbers: Give an array numbers of n integer
* @param target: An integer
* @return: return the sum of the three integers, the sum closest target.
*/
int threeSumClosest(vector<int> &numbers, int target) {
    // write your code here
    int result = INT_MAX;
    if (numbers.size() < 3)
    {
        return 0;
    }

    // 先对数组排序
    sort(numbers.begin(), numbers.end());

    int minValue = INT_MAX;
    // 使用循环固定其中一个数
    for (int i = 0; i < numbers.size() - 2; i++)
    {
        int remainTarget = target - numbers.at(i);
        int temp = twoSumClosest(numbers, i + 1, numbers.size() - 1, remainTarget); // 对剩下的子数组找最接近目标值的两数和
        if (abs(remainTarget - temp) < minValue) // 打擂台,寻找最接近的数
        {
            minValue = abs(remainTarget - temp);
            result = numbers.at(i) + temp;
        }
    }

    return result;
}

// 计算最接近remainTarget的两数和
int twoSumClosest(vector<int> & numbers, int left, int right, int remainTarget)
{
    int result = 0;

    int minValue = INT_MAX;
    while (left < right)
    {
        int sum = numbers.at(left) + numbers.at(right);
        if (sum < remainTarget)
        {
            left++;
            if (abs(remainTarget - sum) < minValue) // 打擂台,寻找最接近的数
            {
                minValue = abs(remainTarget - sum);
                result = sum;
            }
        }
        else if (sum > remainTarget)
        {
            right--;
            if (abs(remainTarget - sum) < minValue) // 打擂台,寻找最接近的数
            {
                minValue = abs(remainTarget - sum);
                result = sum;
            }
        }
        else
        {
            minValue = 0;
            result = numbers.at(left) + numbers.at(right);
            break;
        }
    }

    return result;
}

猜你喜欢

转载自blog.csdn.net/SeeDoubleU/article/details/124621850