LeetCode第16题思悟——最接近的三数之和(3sum-closest)
知识点预告
- 数组预处理:排序;
- 双指针遍历数组的处理方法;
题目要求
给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/3sum-closest
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
示例
给定数组 nums = [-1,2,1,-4], 和 target = 1.
与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2).
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/3sum-closest
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
我的思路
排序后三重循环。需要注意的是去重;基本操作;
public static int threeSumClosest(int[] nums, int target) {
if(nums.length==3){
return nums[0]+nums[1]+nums[2];
}
Arrays.sort(nums);
int minDifference=Integer.MAX_VALUE;
int numLength=nums.length;
int secondStartPoint,thirdStartPoint;
int currentDifference;
int lastMinDifference;
int firstNum;
int secondNum;
int currentSum;
int result=0;
int firstBorder=numLength-2;
int secondBorder=numLength-1;
boolean hasSkip;
for(int i=0;i<firstBorder;i++){
firstNum=nums[i];
secondStartPoint=i+1;
hasSkip=false;
for(int j=secondStartPoint;j<secondBorder;j++){
secondNum=nums[j];
thirdStartPoint=j+1;
lastMinDifference=Integer.MAX_VALUE;
for(int k=thirdStartPoint;k<numLength;k++){
currentSum=firstNum+secondNum+nums[k];
currentDifference=Math.abs(target-currentSum);
if(currentDifference<minDifference){
minDifference=currentDifference;
result=currentSum;
}
if(currentDifference<=lastMinDifference){
lastMinDifference=currentDifference;
}else{
System.out.println("Break");
break;
}
}
}
//跳过第一个
while(i<firstBorder&&nums[i]==firstNum){
i++;
hasSkip=true;
}
if(hasSkip){
i--;
}
}
return result;
}
经过LeetCode第15题思悟,我们知道,可以使用双指针遍历的方法替代内部的双重循环;
优秀解法
//解法A
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;
}
//解法B
public static int threeSumClosest(int[] nums, int target) {
Arrays.sort(nums);
int res = 0;
for (int i = nums.length - 1; i >= nums.length - 3; i--) {
res += Math.abs(nums[i]);
}//Fragment B
if(nums.length == 3)
return nums[0] + nums[1] + nums[2];
for(int i = 0; i <= nums.length - 2; i++) {
for(int l = i + 1, r = nums.length - 1, sum = 0; l < r;) {
sum = nums[i] + nums[l] + nums[r];
if(Math.abs(sum - target) <= Math.abs(res - target))
res = sum;
if(sum > target) {
r --;
}else if(sum < target) {
l ++;
}else {
return res;
}
}
}
return res;
}
差异分析
解法A和解法B的本质是相同的,都是使用双指针遍历数组来实现双重循环的功能;
但是Fragment B的目的是初始化res,但遍历整个数组是没有必要的:只需要将其初始化为数组前三个元素之和即可;对于较大长度的数组来说,也能节约一定时间吧;
知识点回顾
- 数组预处理:排序;
- 双指针遍历数组的处理方法;