给定一个包含 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] ]
static List<List<Integer>> lists;
public static List<List<Integer>> fourSum(int[] nums, int target) {
if (nums.length < 4) {
return new ArrayList<List<Integer>>();
}
//先做排序,方便后面判断
Arrays.sort(nums);
lists = new ArrayList<List<Integer>>();
for (int i = 0; i < nums.length - 3; i++) {
//第一个数字,如果发现跟前面数字相等可以直接忽略,因为没有任何情况还会符合要求,只可能跟前面的可能性重复
//也不必担心有相同数字组成目标解得情况,这个也在前面的循环会遍历到
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
for (int j = i + 1; j < nums.length - 2; j++) {
//第二个数字,也是跟前一数字相等时可以忽略
if (j > i + 1 && nums[j] == nums[j - 1]) {
continue;
}
int res = target - nums[i] - nums[j];
//当i,j确定时算一下当前最大最小值
int maxV = nums[nums.length - 2] + nums[nums.length - 1];
int minV = nums[j + 1] + nums[j + 2];
//如果当前最小值都大于目标值或者当前最大值都小于目标值就不必再往下走了
if (maxV <= res || minV >= res) {
if (maxV == res) {
//如果当前最大值等于target,那这一轮只有这一个符合要求
//添加到list中
List<Integer> temp = new ArrayList<Integer>();
temp.add(nums[i]);
temp.add(nums[j]);
temp.add(nums[nums.length - 2]);
temp.add(nums[nums.length - 1]);
lists.add(temp);
} else if (minV == res) {
//只有当前最小值符合要求
//添加到list中
List<Integer> temp = new ArrayList<Integer>();
temp.add(nums[i]);
temp.add(nums[j]);
temp.add(nums[j + 1]);
temp.add(nums[j + 2]);
lists.add(temp);
}
continue;
}
//从两端往中间夹逼
int left = j + 1;
int right = nums.length - 1;
while (left < right) {
if (nums[left] + nums[right] > res) {
//大于目标值,右端左移
right--;
while (left < right) {
//对数字相同情况的判断
if (nums[right] == nums[right + 1]) {
right--;
} else {
break;
}
}
} else if (nums[left] + nums[right] < res) {
//小于目标值,左端右移
left++;
while (left < right) {
//对数字相同情况的判断
if (nums[left] == nums[left - 1]) {
left++;
} else {
break;
}
}
} else {
//添加到list中
List<Integer> temp = new ArrayList<Integer>();
temp.add(nums[i]);
temp.add(nums[j]);
temp.add(nums[left]);
temp.add(nums[right]);
lists.add(temp);
//这里要考虑到下一元素和当前元素有可能相等,为避免重复要进行判断
left++;
while (left < right) {
if (nums[left] == nums[left - 1]) {
left++;
} else {
break;
}
}
right--;
while (left < right) {
if (nums[right] == nums[right + 1]) {
right--;
} else {
break;
}
}
}
}
}
}
return lists;
}