描述
该题来自于力扣第16题
给定一个包括n个整数的数组nums和一个目标值target。找出nums中的三个整数,使得它们的和与target最接近。返回这三个数的和。假定每组输入只存在唯一答案。
示例:
输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。
提示:
3 <= nums.length <= 10^3
-10^3 <= nums[i] <= 10^3
-10^4 <= target <= 10^4
分析
首先想到三数之和的解法,将数组排序,然后先固定第一个数,接下来就是如何找到另外两个数,使得三个数的和最接近target。还是用双指针法,假设第一个数下标为first,第二个数下标为second=first+1,第三个数下标为third=n-1,记s=nums[first]+nums[second]+nums[third],由于数组是排过序的,所以分三种情况
1.
如果s=target,直接返回这target就可以了;
2.
如果s>target,那么移动指针second,只会让s更大,从而与target相差更大,所以让third--;
3.
如果s<target,那么移动指针third,只会让s更小,从而与target相差更大,所以让second--
经过上述步骤,如果没有返回,记录s-target的绝对值是否是最小的,并更新s,然后遍历first就可以找到最终结果了。
## 算法
1. 排序数组
2.
将最接近target的值closest初始化为nums[0]+nums[1]+nums[2]
3.
第一个数下标first从0到n-3遍历数组
4.
进入循环体,设second=first + 1,third=n-1,计算s=nums[first] + nums[second] + nums[third]
5.
判断s与target的关系,如果s==target,直接返回target,退出程序;否则按照上面的分析更新second,third
6.
如果|s-target|<|closest-target|,那么更新closest=s
7.
判断second是否大于等于third,如果是,退出循环;否则first++,并进入循环体(第4步)
小优化:
在三数之和中,为了避免找到重复解,每到一个新数时可以和前面数比较,如果一样直接跳过。这里在遍历first,second,third三个数时都可以跳过重复值,避免重复计算。
## 代码
python3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class Solution : def threeSumClosest (self, nums, target ): nums.sort() closest = sum (nums[:3 ]) first = 0 while first < len (nums) - 2 : second, third = first + 1 , len (nums) - 1 while second < third: s = nums[first] + nums[second] + nums[third] if abs (s - target) <= abs (closest - target): closest = s if closest == target: return target if s > target: while third > second and nums[third] == nums[third-1 ]: third -= 1 third -= 1 elif s < target: while second < third and nums[second] == nums[second+1 ]: second += 1 second += 1 while first < len (nums) - 2 and nums[first] == nums[first+1 ]: first += 1 first += 1 return closest
c++
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class Solution {public : int threeSumClosest (vector<int >& nums, int target) { sort (nums.begin (), nums.end ()); int first = 0 ; int closest = nums[0 ] + nums[1 ] + nums[2 ]; while (first < nums.size () - 2 ) { int second = first + 1 ; int third = nums.size () - 1 ; while (second < third) { int s = nums[first] + nums[second] + nums[third]; if (abs (s - target) <= abs (closest - target)) { closest = s; if (closest == target) return target; } if (s > target) { while ((third > second) && (nums[third] == nums[third-1 ])) third--; third--; } else if (s < target) { while ((second < third) && (nums[second] == nums[second + 1 ])) second++;; second++; } } while ((first < nums.size () - 2 ) && (nums[first + 1 ] == nums[first])) first++; first++; } return closest; } };
java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class Solution { public int threeSumClosest (int [] nums, int target) { Arrays.sort(nums); int first = 0 ; int closest = nums[0 ] + nums[1 ] + nums[2 ]; while (first < nums.length - 2 ){ int second = first + 1 ; int third = nums.length - 1 ; while (second < third){ int s = nums[first] + nums[second] + nums[third]; if (Math.abs(s - target) <= Math.abs(closest - target)){ closest = s; } if (closest == target) return target; if (s > target){ while ((third > second) && (nums[third] == nums[third-1 ])) third--; third--; } else if (s < target){ while ((second < third) && (nums[second] == nums[second+1 ])) second++; second++; } } while ((first < nums.length - 2 ) && (nums[first] == nums[first+1 ])) first++; first++; } return closest; } }