package day04;
/*
给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,
使得 a + b + c + d 的值与 target 相等?
找出所有满足条件且不重复的四元组。
*/
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class FourNumberSum {
public static void main(String[] args) {
int [] nums = {1,0,-1,0,-2,2};
int target = 0;
List<List<Integer>> res = fourSum(nums, target);
System.out.println(res);
}
public static List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> res = new ArrayList<>();
if(nums == null || nums.length < 3){
return res;
}
int len = nums.length;
Arrays.sort(nums);
for(int i = 0; i < len - 3; i++) {
//去掉重复的值
if(i > 0 && nums[i] == nums[i - 1]) {
continue;
}
//获取当前的最小值与目标值比较,如果当前的最小值比目标值还大,后面只会越来越大
int curMin = nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3];
if(curMin > target) {
break;
}
//获取当前的最大值与目标值比较,如果当前的最大值比目标值还小,后面只会越来越小
int curMax = nums[i] + nums[len - 1] + nums[len - 2] + nums[len - 3];
if(curMax < target) {
continue;
}
//否则,开始第二层循环
for(int j = i + 1; j < len - 2; j ++) {
//去掉重复的部分
if(j > i + 1 && nums[j] == nums[j - 1]) {
continue;//注意,这里是跳到下一次循环,而不是break
}
int m = j + 1;
int n = len - 1;
//获取当前的最小值与目标值比较,如果当前的最小值比目标值还大,后面只会越来越大,此时前两个数已定为nums[i], nums[j]
int curMin2 = nums[i] + nums[j] + nums[m] + nums[m + 1];
if(curMin2 > target) {
continue;//注意,这里是跳到下一次循环,而不是break
}
//获取当前的最大值与目标值比较,如果当前的最大值比目标值还小,后面只会越来越小,此时前两个数已定为nums[i], nums[j]
int curMax2 = nums[i] + nums[j] + nums[n] + nums[n - 1];
if(curMax2 < target) {
continue;//注意,这里是跳到下一次循环,而不是break
}
//否则开始和target比较
while (m < n) {
int curNum = nums[i] + nums[j] + nums[m] + nums[n];
if(curNum < target) {
m += 1;
} else if (curNum > target) {
n -= 1;
} else {
List<Integer> tmp = new ArrayList<>();
tmp.add(nums[i]);
tmp.add(nums[j]);
tmp.add(nums[m]);
tmp.add(nums[n]);
res.add(tmp);
//去重
m += 1;
while (m < n && nums[m] == nums[m - 1]) {
m ++;
}
n -= 1;
while (m < n && nums[n] == nums[n + 1]) {
n --;
}
}
}
}
}
return res;
}
}