题目
首先看到题目是不是想到就不过是求最接近的麻 ,简单,直接几个循环套上去得了
这样可以但是时间复杂度怎么办o(n^3)应该是有的.
思路
首先我们应该想到双指针的方法.诶?双指针怎么处理三个量呢?
双指针是不是都是从一个数组的start和end开始的吗??
那么只要我们实现每次遍历变它们后改变start和endde 初始值就行了
对于代码,我们第一件要做的事是对数组进行由大到小的排序 可以用sort的方法快速完成,这是为了双指针移动时的条件为前后两次绝对值大小比较的结果
再用math.abs去求绝对值,在比较前后两次绝对值的大小就行了
代码实现
public int threeSumClosest(int[] nums, int target) {
Arrays.sort(nums);
int ans = nums[0] + nums[1] + nums[2];
for(int i=0;i<nums.length;i++) {
int start = i+1, end = nums.length - 1;
while(start < end) {
int sum = nums[start] + nums[end] + nums[i];
if(Math.abs(target - sum) < Math.abs(target - ans))
ans = sum;
if(sum > target)
end--;
else if(sum < target)
start++;
else
return ans;
}}
return ans;
}
那么这就是一个简单的双指针代码了可以看到
这里仅仅只超过了20%的用户,那剩下的80%的人是怎么做到的呢/?
代码优化
1.元素重复的问题 举个例子,nums = [1,1,1,2,3] target = 7,那么最终的结果应该是 6 (1 + 2 + 3)。
但是按照上面的代码,在遍历的时候 nums[i]会重复的等于 1 这个数,但是其实之前 nums[i] 等于 1 已经遍历过了,后面的遍历都属于无用的遍历。
所以可以添加去重的操作
2.超越界限的问题 举个例子,nums = [-3,-1,3,4,5]。 假设 i = 0,left = 1,right = 4,那么每次 left 和 right 之间都有许多元素,那么 left 和 right 之间的元素之和肯定也有一个最小值和一个最大值。
就如同 left = 1,right = 4,那么移动指针的情况下,nums[left] + nums[right] 的最小值肯定为 nums[left] + nums[left + 1],因为这两个元素是 left 和 right 范围内能取到的最小的两个元素,同理可证最大值。
如果 target 的值比 nums[i] + nums[left] + nums[left + 1] 的值还小,那么双指针无论怎么取,最后都会取到 nums[i] + nums[left] + nums[left + 1]。 同理可证 target 的值比nums[i] + nums[right] + nums[right - 1] 的值还大的情况。 所以可以增加一个判断,满足条件的情况下就可以直接取值,而不需要双指针一步步的判断来进行取值,减少了双指针的移动。
3.三数之和等于 target 的问题 举个例子,nums = [1,1,2,3,4,5,6,10] target = 12,那么最终的结果应该是 12 (1 + 1 + 10)。 有些时候,可能会直接找到三数之和等于 target 的情况,此时直接返回结果即可,不需要在进行之后的循环,因为不可能有数比他自己更接近自己了。
4.完整代码
public int threeSumClosest(int[] nums, int target) {
Arrays.sort(nums);
int result = nums[0] + nums[1] + nums[2];
for(int i=0;i<nums.length-2;i++){
int left = i+1;
int right = nums.length - 1;
while(left != right){
int min = nums[i] + nums[left] + nums[left + 1];
if(target < min){
if(Math.abs(result - target) > Math.abs(min - target))
result = min;
break;
}
int max = nums[i] + nums[right] + nums[right - 1];
if(target > max){
if(Math.abs(result - target) > Math.abs(max - target))
result = max;
break;
}
int sum = nums[i] + nums[left] + nums[right];
// 判断三数之和是否等于target
if(sum == target)
return sum;
if(Math.abs(sum - target) < Math.abs(result - target))
result = sum;
if(sum > target){
right--;
while(left != right && nums[right] == nums[right+1])
right--;
}
else{
left++;
while(left != right && nums[left] == nums[left-1])
left++;
}
}
while(i<nums.length-2 && nums[i] == nums[i+1])
i++;
}
return result;
}
这样处理完那么就超过99.9%的用户了
小编也是看大神的文章才成为那个0.1%