使用两重循环分别枚举前两个数,然后在两重循环枚举到的数之后使用双指针枚举剩下的两个数。假设两重循环枚举到的前两个数分别位于下标 i 和 j,其中 i<j。初始时,左右指针分别指向下标 j+1 和下标 n-1。每次计算四个数的和,并进行如下操作:
如果和等于target,则将枚举到的四个数加到答案中,然后将左指针右移直到遇到不同的数,将右指针左移直到遇到不同的数;
如果和小于 target,则将左指针右移一位;
如果和大于target,则将右指针左移一位。
使用双指针枚举剩下的两个数的时间复杂度是 O(n),因此总时间复杂度是 O(n^3),低于 O(n^4)。
public static List<List<Integer>> fourSum(int[] nums, int target){
List list = new ArrayList();
boolean flagg=true;
int len=nums.length;
if(len<4) //[][0][0,0]的结果都是[]
return list;
Arrays.sort(nums);
for (int i=0;i<len-1; i++) {
// 需要和上一次枚举的数不相同
if (i > 0 && nums[i] == nums[i - 1])
continue;
for (int j = i+1;j<len;j++){
if (j > i+1 && nums[j] == nums[j - 1])
continue;
int sum = target - nums[i] -nums[j];
int begin = j + 1;
int end = len - 1;
while (begin < end) {
int rsum = nums[begin] + nums[end];
if (rsum > sum)
end--;
if (rsum < sum)
begin++;
if (rsum == sum) {
List<Integer> listsmall = new ArrayList<Integer>();
listsmall.add(nums[i]);
listsmall.add(nums[j]);
listsmall.add(nums[begin]);
listsmall.add(nums[end]);
list.add(listsmall);
//可能存在多解,跳过相同字符
//多解 不存在相同字符:-1 -1 0 1 2 固定第0个-1(-1,-1,2)(-1,0,1)
//多解 存在相同字符:-1 -1 -1 0 1 2 固定第0个-1(-1,-1,2)(-1,-1(第二个),2),这里的第二个-1就需要跳过,不然会有重复解
while (begin < end && nums[begin + 1] == nums[begin]) {
begin++;
}
begin++;
while (begin < end && nums[end - 1] == nums[end]) {
end--;
}
end--;
}
}
}
}
return list;
}