1、三数和为0:
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例:
给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
#题解:
看评论发现了一个用到指针的算法快速且容易理解,所以在经过理解和自己复写一遍后在此留下笔记。其方法主要是:1、数组从小到大排序;2、循环遍历数组确定三元组中的最小的第一个数nums[i];3、令L=i+1、R=nums.length-1;4、在固定nums[i]的前提下让L和R夹逼,途中把满足条件的三元组添加到lists中;5、遍历途中nums[i+1]==nums[i]则直接跳过,循环直到nums[i]>0结束。
代码:
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List <List<Integer>> lists=new ArrayList<>();
Arrays.sort(nums);
if(nums.length<3) return lists;
for(int i=0;i<nums.length-2;i++){ //遍历三数的最小数
int L=i+1;
int R=nums.length-1;
if(i>0 && nums[i]==nums[i-1]) continue;
while(L<R){ //双指针运动确定剩下两个数
if(nums[i]>0) return lists;
int tmp=nums[i]+nums[L]+nums[R];
if(tmp==0){
lists.add(Arrays.asList(nums[i],nums[L],nums[R]));
while(L<R && nums[L+1]==nums[L]) L++;
while(L<R && nums[R-1]==nums[R]) R--;
L++;
R--;
}
else if(tmp<0)
L++;
else if(tmp>0)
R--;
}
}
return lists;
}
}
2、三数和最接近目标数:
给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。
例如,给定数组 nums = [-1,2,1,-4], 和 target = 1.
与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2).
#题解:
用上述指针思路,不过有点暴力不算优:
class Solution {
public int threeSumClosest(int[] nums, int target) {
if(nums.length<3) return 0;
int totarget=999999;
int Sums=0;
Arrays.sort(nums);
//[-1,0,1,1,55]
for(int i=0;i<nums.length-2;i++){
int L=i+1;
int R=nums.length-1;
while(L<R){
int sum=nums[i]+nums[L]+nums[R];
if(Math.abs(sum-target)<totarget){
totarget=Math.abs(sum-target);
Sums=sum;
}
if(sum==target) return Sums;
else if(sum<target) L++;
else if(sum>target) R--;
}
}
return Sums;
}
}
3、四数和为目标数:
给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。
注意:
答案中不可以包含重复的四元组。
示例:
给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。
满足要求的四元组集合为:
[
[-1, 0, 0, 1],
[-2, -1, 1, 2],
[-2, 0, 0, 2]
]
#题解:
此题跟三数和为0是一样的,只是要多一层嵌套循环。三数时只需要把最小数遍历,然后指针移动剩余两数即可。而四数则需要双层嵌套遍历最小的两个数,再把剩下的两个数进行指针移动。注意:如何避免输出重复解是此题最容易出错的地方,我自己提交报错了好几次才完全解决。
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List <List<Integer>> result=new ArrayList<>();
if(nums.length<4 || nums==null) return result;
Arrays.sort(nums);
for(int i=0;i<nums.length-3;i++){ //遍历四数中的最小数
int R=nums.length-1;
if(nums[i]+nums[i+1]+nums[i+2]+nums[i+3]>target) break;
if(nums[i]+nums[R]+nums[R-1]+nums[R-2]<target) continue;
if(i>0 && nums[i]==nums[i-1]) continue; //去重复解
for(int j=i+1;j<nums.length-2;j++){ //遍历第二小的数
int L=j+1;
R=nums.length-1;
if(nums[i]+nums[j]+nums[R-1]+nums[R]<target) continue;
if(j>i+1 && nums[j]==nums[j-1]) continue; //去重复解
while(L<R){ //对剩下的两个数进行左右指针运动
if(nums[i]+nums[j]+nums[L]+nums[R]==target){
result.add(Arrays.asList(nums[i],nums[j],nums[L],nums[R]));
while(L<R && nums[L+1]==nums[L]) L++; //去重复解
while(L<R && nums[R-1]==nums[R]) R--;
L++;
R--;
}
else if(nums[i]+nums[j]+nums[L]+nums[R]<target) L++;
else if(nums[i]+nums[j]+nums[L]+nums[R]>target) R--;
}
}
}
return result;
}
}