题目链接
思路:排序+双指针
分析:首先排序,第一个是为了从小到大遍历每一个数,第二个是为了去重方便,排序完相同的数肯定是靠在一起的。
第一:遍历第一个数,从小到大。
第二:遍历第二个数,从小到大。
第三:计算第一个数与第二个数的和,然后再计算与目标之的差距。
第四:此时题目就变成了,从第二个数后面开始找两个数相加等于这个差距。此时因为是有序的,所以可以用双指针来查找。
这里还可以减枝来提高效率。
代码:
class Solution {
List<List<Integer>> res = new ArrayList<>();
List<Integer> seqr = new ArrayList<>();
public List<List<Integer>> fourSum(int[] nums, int target) {
if(nums.length<4){
return res;
}
Arrays.sort(nums);
if((long)nums[0]+nums[1]+nums[2]+nums[3]>target){
return res;
}
int len = nums.length;
if((long)nums[len-1]+nums[len-2]+nums[len-3]+nums[len-4]<target){
return res;
}
for(int i=0; i<nums.length-3; i++){
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[len - 3] + nums[len - 2] + nums[len - 1] < target) {
continue;
}
//加第一个数
seqr.add(nums[i]);
for(int j=i+1; j<nums.length-2;j++){
if(j-1!=i && 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[len - 2] + nums[len - 1] < target) {
continue;
}
//加第二个数
seqr.add(nums[j]);
int tar = target - nums[i] - nums[j];
//也就是说,现在需要从nums的[j+1,len-1]找到两个数相加等于tar的
int l = j+1;
int r=nums.length-1;
while(l<r){
if(nums[l]+nums[r]==tar){
seqr.add(nums[l]);
seqr.add(nums[r]);
//添加答案
res.add(new ArrayList<>(seqr));
seqr.remove(2);
seqr.remove(2);
//三层去重
do{
l++;
}while(l<r && nums[l]==nums[l-1]);
//四层去重
do{
r--;
}while(l<r && nums[r]==nums[r+1]);
}else if(nums[l]+nums[r]<tar){
l++;
}else{
r--;
}
}
seqr.remove(1);
}
seqr.remove(0);
}
return res;
}
}