题目描述:
给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):
0 <= a, b, c, d < n
a、b、c 和 d 互不相同
nums[a] + nums[b] + nums[c] + nums[d] == target
你可以按 任意顺序 返回答案 。
思路:
和三数之和有一点不同!不能使用 > 0作为return条件;内层的for循环返回条件不定!
注意细节的处理!
1)两层for循环,处理前两个数字;后两个数字使用双指针进行解决!
2)要理解:使用for循环枚举的时候,第二层的循环不用再从头找!只用从第一层循环的 i+1处开始即可,之前的情况已经全部包含!
3)Collections.sort(int[] arr);将数组排序
if(!res.contains(ans)) res.add(ans);
一个去重的方法!
4)会有溢出问题,可以转换为 long型的,强转!
代码:
1)排序 + 两层for循环 + 双指针
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(nums);
for(int i = 0;i < nums.length;i++){
//处理和 三数之和不一样!
//这里不能用 > 0作为返回标志!
//if(nums[i] > target) return res;
if(i > 0 && nums[i] == nums[i - 1]) continue;
//可以往下走
for(int j = i+1;j < nums.length;j++){
//这里怎么处理,跳出内层的for循环
//这里不能时return,应该是结束本次循环!修改i值
//if(nums[j] >= target) continue;
if(j > i + 1 && nums[j] == nums[j - 1]) continue;
int m = j + 1;
int n = nums.length - 1;
while(m < n){
if(nums[i] + nums[j] + nums[m] + nums[n] > target) n--;
else if(nums[i] + nums[j] + nums[m] + nums[n] < target) m++;
else{
res.add(Arrays.asList(nums[i],nums[j],nums[m],nums[n]));//结果加到结果列表
//跳过重复的结果
while(m < n && nums[m] == nums[m + 1]) m++;
while(m < n && nums[n] == nums[n - 1]) n--;
//如果while判断过,就走到了边界;没判断也是边界;都需要往后移动
m++;
n--;
}
}
}
}
return res;
}
}
2)加了两个边界条件的判定,优化很多!
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(nums);
int length = nums.length;
for(int i = 0;i < nums.length - 3;i++){
//处理和 三数之和不一样!
//这里不能用 > 0作为返回标志!
//if(nums[i] > target) return res;
if(i > 0 && nums[i] == nums[i - 1]) continue;
if((long)nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) break;
if((long)nums[i] + nums[length - 3] + nums[length - 2] + nums[length - 1] < target){
continue;
}
//可以往下走
for(int j = i+1;j < nums.length - 2;j++){
//这里怎么处理,跳出内层的for循环
//这里不能时return,应该是结束本次循环!修改i值
//if(nums[j] >= target) continue;
if(j > i + 1 && nums[j] == nums[j - 1]) continue;
if((long)nums[i] + nums[j] + nums[j+1] + nums[j+2] > target) break;
if((long)nums[i] + nums[j] + nums[length - 2] + nums[length - 1] < target) continue;
int m = j + 1;
int n = nums.length - 1;
while(m < n){
if((long)nums[i] + nums[j] + nums[m] + nums[n] > target) n--;
else if((long)nums[i] + nums[j] + nums[m] + nums[n] < target) m++;
else{
res.add(Arrays.asList(nums[i],nums[j],nums[m],nums[n]));//结果加到结果列表
//跳过重复的结果
while(m < n && nums[m] == nums[m + 1]) m++;
while(m < n && nums[n] == nums[n - 1]) n--;
//如果while判断过,就走到了边界;没判断也是边界;都需要往后移动
m++;
n--;
}
}
}
}
return res;
}
}