相关主题:Array, two pointers
using Java
题目
15 Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
16 Given an array nums of n integers and an integer target, find three integers in nums such that the sum is closest to target. Return the sum of the three integers. You may assume that each input would have exactly one solution.
难度
都是medium
思路异同
相同点
因为是判断3个数的和,都是先固定一个数fix,然后转化成2个数的和的问题,具体方案是:先将数组由小到大排序,然后遍历数组到n-2个数,每次从fix的后面找另外2个数(因为3个数里包括该数前面的数的情况已经考虑过了),设置left,right分别指向fix后一个数和数组的最后一个数(即主题中的two pointers)。
不同点
15 因为和要恰好等于一个数(0),并且满足条件的三个数不只一种都要输出,所以在while(left<right)的循环里要分三种情况,尤其在满足两数和==-fix(目标和0减去fix)时,既要添加三个数到结果List里,又要分别处理left,right;两数和<-fix,left+1;两数和>-fix,right-1。
16 因为要最接近target,并且只需要输出最接近target的值,所以每次循环都要计算当前和target之前的差距,与之前距离最小值对比。
代码
15 3sum
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> ans=new ArrayList<>();
Arrays.sort(nums);
for(int i=0;i<nums.length-2;i++){
//剪枝,如果已经大于0了再往后面找无论如何结果大于0
if(nums[i]>0) break;
//如果和前一个一样证明重复,不需要在考虑
if(i>0&&nums[i]==nums[i-1]) continue;
int fix=nums[i];
//需要找一个两个数之和为target的
int target=0-fix;
int left=i+1;
int right=nums.length-1;
while(left<right){
if(nums[left]+nums[right]==target){
List<Integer> nowl =Arrays.asList(fix,nums[left],nums[right]);
ans.add(nowl);
while(left<right&&nums[left+1]==nums[left]) left++;
while(left<right&&nums[right-1]==nums[right]) right--;
left++;
right--;
}else if(nums[left]+nums[right]<target){
left++;
}else{
right--;
}
}
}
return ans;
}
}
16 3sum closest
class Solution {
public int threeSumClosest(int[] nums, int target) {
//一个比较合理的初始化值
int ans=nums[0]+nums[1]+nums[2];
Arrays.sort(nums);
for(int i=0;i<nums.length-2;i++){
//优化效果并不明显
if(nums[i]*3>target)
return Math.min(ans,nums[i]+nums[i+1]+nums[i+2]);
//如果和前一个一样证明重复,不需要在考虑
if(i>0&&nums[i]==nums[i-1]) continue;
int fix=nums[i];
int left=i+1;
int right=nums.length-1;
while(left<right){
int dis=fix+nums[left]+nums[right]-target;
if(Math.abs(dis)<Math.abs(ans-target)){
ans=fix+nums[left]+nums[right];
}
if(dis<0){
left++;
}else{
right--;
}
}
}
return ans;
}
}
注意点
15
- 第6行剪枝的应用:因为数组已经是排序过的,如果已经大于0了再往后面找无论如何结果大于0;所以如果已经大于0了可以不继续查找(break)
- 注意排除重复的情况:在遍历的时候如果与前一个数等,跳过(continue);两数和已经和-fix相等的时候,如果nums[left+1]和nums[left]相等,那么left++;同理nums[right-1]和nums[right]相等,那么right- -。
16
- 最好用一个变量表示和与target的差距,另一个变量表示和,这样思路更清晰。