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 源码
细节:
- 需要先对数组排序。
- 使用循环固定其中一个数,再在剩下的子数组中寻找最接近新目标值的两个数。
- 使用打擂台的方式,寻找最接近的值。
C++版本:
/**
* @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;
}