题目描述
给定一个包括 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
暴力法
枚举所有可能的情况,时间复杂度o(n^3)。暴力解法很少会成为我们最终满意的答案,效率十分低下。那为什么还要写暴力解法。首先暴力解法可以让我们发现代码在什么方面还有优化的空间,二来,暴力解法可以为我们提供一个正确答案的参考,因为暴力解法的计算出的答案肯定是没问题的。
public static int threeSumClosest2(int[] nums, int target) {
int ans=3001;
for (int left = 0; left < nums.length - 2; left++) {
for (int mid = left + 1; mid < nums.length - 1; mid++) {
for (int right = mid + 1; right < nums.length; right++) {
int sum=nums[left]+nums[mid]+nums[right];
ans=Math.abs(sum-target)<Math.abs(ans-target)?sum:ans;
}
}
}
return ans;
}
暴力法优化
题目要求选择三个数,若是我们对数组排好序,那么我们就可以像二分查找那样,三个数之和大于目标数则抛弃一个较大的数字选择一个更小的数字,若是小于目标数字则抛弃一个较小的数字选择一个较大的数字。
排序后,我们依次枚举最小数字作为第一个数字,然后选择数组中的最大值作为第三个数字。第二个数字则在最小数字和最大数字中间。若三个数字和较大则指向最大数字的指针前移,否则指向中间数字的指针后移。
public static int threeSumClosest(int[] nums, int target) {
Arrays.sort(nums);
int minAbs = 3001;
int ans = 0;
for (int left = 0; left < nums.length; left++) {
int mid = left + 1, right = nums.length - 1;
while (mid < right) {
int sum = nums[left] + nums[mid] + nums[right];
if (sum > target) {
right--;
if (sum - target < minAbs) {//更新最接近数字
minAbs = sum - target;
ans = sum;
}
} else if (sum < target) {
mid++;
if (target - sum < minAbs) {//更新最接近数字
minAbs = target - sum;
ans = sum;
}
} else return target;
}
}
return ans;
}
虽然仍然不是最优解,但是效率也还可以,时间复杂度为o(n^2).