1. 题目
给你一个长度为 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
从题目和要求来看,就可以知道。它和上一题其实差不多,只是一个简单的变种而已。
2. 解题
然后,我尝试自己写算法,错误了10次以及多次超出时间限制后.
例如下面的错误示例:在160个示例时超时。不通过。
class Solution {
public int threeSumClosest(int[] nums, int target) {
int max = nums.length;
int a, b, c;// 三个数
Arrays.sort(nums);
int value = Integer.MAX_VALUE;
int tmp;
int len, tmpLen, tmp1 = -1, tmpMin = 3000, tmpMinLen = -1;
int tempB;
len = Math.abs(target - value);
for (int i = 0; i < max; ++i) {
a = nums[i];
if (i > 0 && a == nums[i - 1]) {
continue;
}
b = i + 1;
c = b + 1;
while (b < max && c < max) {
tempB = nums[b];
tmp = a + tempB + nums[c];
if (tmp == target) {
return tmp;
}
tmpLen = Math.abs(target - tmp);
if (tmpLen < len) {
value = tmp;
len = tmpLen;
}
if (tmpMinLen == -1 || tmpMinLen > tmpLen) {
tmpMin = tmp;
tmpMinLen = tmpLen;
}
//tmp 只会越来越大,超过0之后就可以不用判断了。
if (tmp > 0) {
//大于零会变大
c = max - 1;
} else if (tmp1 >= 0 && tmp1 < tmpLen) {
// 小于0 会变小
c = max - 1;
}
tmp1 = tmpLen;
if (c + 1 == max) {
++b;
while (b < max) {
if (nums[b] == tempB) {
++b;
} else if (target == (nums[b] - tempB + tmpMin)) {
return target;
} else if (Math.abs(target - (nums[b] - tempB + tmpMin)) < len) {
break;
} else {
++b;
}
}
c = b + 1;
} else {
while (c + 1 < max && nums[c] == nums[c + 1]) {
++c;
}
++c;
}
}
}
return value;
}
}
多次撞墙后,通过其他大神的解法,示例:
class Solution {
public int threeSumClosest(int[] nums, int target) {
Arrays.sort(nums);
int len = nums.length, closestNum = Integer.MAX_VALUE, sum, left = 1, right = len - 1;
for (int i = 0; i < len - 2; i++, left = i + 1, right = len - 1) {
while (left < right) {
if ((sum = nums[i] + nums[left] + nums[right]) == target) return target;
if (Math.abs(sum - target) < Math.abs(closestNum - target)) closestNum = sum;
if (sum < target) do left++; while (left < right && nums[left] == nums[left + 1]);
else do right--; while (left < right && nums[right] == nums[right - 1]);
}
}
return closestNum;
}
}
执行用时: 67 ms
内存消耗: 41.2 MB
通过了验证,然后发现自己果然是个傻子。
如果上面的示例还不能太理解的话,可以看看官方示例:带注解
class Solution {
public int threeSumClosest(int[] nums, int target) {
Arrays.sort(nums);
int n = nums.length;
int best = 10000000;
// 枚举 a
for (int i = 0; i < n; ++i) {
// 保证和上一次枚举的元素不相等
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
// 使用双指针枚举 b 和 c
int j = i + 1, k = n - 1;
while (j < k) {
int sum = nums[i] + nums[j] + nums[k];
// 如果和为 target 直接返回答案
if (sum == target) {
return target;
}
// 根据差值的绝对值来更新答案
if (Math.abs(sum - target) < Math.abs(best - target)) {
best = sum;
}
if (sum > target) {
// 如果和大于 target,移动 c 对应的指针
int k0 = k - 1;
// 移动到下一个不相等的元素
while (j < k0 && nums[k0] == nums[k]) {
--k0;
}
k = k0;
} else {
// 如果和小于 target,移动 b 对应的指针
int j0 = j + 1;
// 移动到下一个不相等的元素
while (j0 < k && nums[j0] == nums[j]) {
++j0;
}
j = j0;
}
}
}
return best;
}
}
执行用时:80 ms
内存消耗:41.6 MB
官方的示例,明显更耗时,有不少解法官方并不是最高效的。人民群众中的大神更多哦。
参考链接:
评论区