题目
给你一个长度为 n
的整数数组 nums
和 一个目标值 target
。请你从 nums
中选出三个整数,使它们的和与 target
最接近。
返回这三个数的和。
假定每组输入只存在恰好一个解。
示例 1:
输入:nums = [-1,2,1,-4], target = 1 输出:2 解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。
示例 2:
输入:nums = [0,0,0], target = 1 输出:0
提示:
3 <= nums.length <= 1000
-1000 <= nums[i] <= 1000
-104 <= target <= 104
提交代码
//最接近的三数之和
//三个数,两次双指针
//解可能等于、大于、小于target
//最接近target
//先排序
//唯一解
//等于target直接返回
//用两个变量存小于target的最大值和大于target的最小值
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
vector<int> nums;//整数数组
int target;//目标值
int n;//整数数组长度
int res1 = -100000,res2 = 100000;//小于target的最大值和大于target的最小值
int result;//结果
//两次双指针算法
void tsc(){
int i = 0;//最小数的下标,双指针
while(i < n - 2){
if(nums[i] + nums[n - 2] + nums[n - 1] == target){
result = target;
return;
}else if(nums[i] + nums[i + 1] + nums[i + 2] > target){
//不可能有更接近的解了
if(res2 > nums[i] + nums[i + 1] + nums[i + 2]){
res2 = nums[i] + nums[i + 1] + nums[i + 2];
}
break;
}else if(nums[i] + nums[n - 2] + nums[n - 1] < target){
if(i == n - 3){
//不会有更接近的解了
result = nums[i] + nums[n - 2] + nums[n - 1];
return;
}
res1 = nums[i] + nums[n - 2] + nums[n - 1];
i++;
}else if(nums[i] + nums[n - 2] + nums[n - 1] > target){
int j = i + 1,k = n - 1;//双指针
while(j < k){
if(nums[i] + nums[j] + nums[k] == target){
result = target;
return;
}else if(nums[i] + nums[j] + nums[k] < target){
if(res1 < nums[i] + nums[j] + nums[k]){
res1 = nums[i] + nums[j] + nums[k];
}
j++;
}else if(nums[i] + nums[j] + nums[k] > target){
if(res2 > nums[i] + nums[j] + nums[k]){
res2 = nums[i] + nums[j] + nums[k];
}
k--;
}
}
i++;
}
}
result = (target - res1) > (res2 - target) ? res2 : res1;
}
int main(){
//输入数组
int t;//存储整数
while(cin.peek() != '\n'){
scanf("%d",&t);
nums.push_back(t);
}
//输入目标值
scanf("%d",&target);
//-------------------------------
n = nums.size();//数组长度
//给数组排序
sort(nums.begin(),nums.end());
//两次双指针算法
tsc();
//输出结果
printf("%d",result);
return 0;
}
总结
解题思路:求最接近的解,容易想到暴力解法,可以使用双指针进行剪枝,排除掉不可能的一系列情况,优化时间。依旧是两次嵌套使用双指针算法,最外层的第一层双指针判断最小数可能的位置(自己事先排序),不可能的位置直接跳过,内层第二次双指针算法在第一次排除的基础上,用两个指针下标对每个元素进行一次判断就可以,总体的时间复杂度为O(n^2)。外层第一次双指针算法在筛选时,如果nums[i] + nums[n - 2] + nums[n - 1] < target,证明最小数为nums[i]时,不可能有大于target的解,最接近target的值一定未nums[i] + nums[n - 2] + nums[n - 1],其他情况不需要计算;如果nums[i] + nums[n - 2] + nums[n - 1] > target,需要进行第二次双指针判断;如果nums[i] + nums[i + 1] + nums[i + 2] > target,表明最小数为nums[i]时,不可能有小于target的解,且后续不可能有比nums[i] + nums[i + 1] + nums[i + 2]更小的解了,可以跳出第一次双指针算法。分别用res1和res2存储小于target的最大值和大于target的最小值,最后统一比较。
注意:第二次双指针算法结束后,不要忘记i++;