题目:
给你一个由 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
你可以按 任意顺序 返回答案 。
public class 四数之和 {
public static void main(String[] args) {
int[] nums = {-2,-1,-1,1,1,2,2};
System.out.println( fourSum(nums, 0));
}
public static List<List<Integer>> fourSum(int[] nums, int target) {
List result = new ArrayList();
if (nums == null || nums.length < 4) { //nums 为空或者长度小于4直接返回
return new ArrayList();
}
//先排序;这样使用双指针就很方便
Arrays.sort(nums);
int b = 0, c = 0, d = 0;
int nn = nums.length;
for (int i = 0; i < nn - 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[nn - 3] + nums[nn - 2] + nums[nn - 1] < target) {
continue;
}
for (b = i + 1; b < nn - 2; b++) { //第二层循环(此刻和三数之和一样的)
if (b > i + 1 && nums[b] == nums[b - 1]) { //防止遍历的元素重复
continue;
}
c = b + 1; //左指针
d = nn - 1; //右指针
while (c < d) {
//和小于target,那么左指针需要右移
if (nums[i] + nums[b] - target < -(nums[c] + nums[d])) {
c++;
}
//和大于target,那么右指针需要左移
else if (nums[i] + nums[b] - target > -(nums[c] + nums[d]))//同上
{
d--;
} else {//值相等了
List list = new ArrayList();
list.add(nums[i]);
list.add(nums[b]);
list.add(nums[c]);
list.add(nums[d]);
result.add(list);
while (c < d && nums[c] == nums[c+1]) { //避免重复
c++;
}
c++;
while (c < d && nums[d] == nums[d-1]) { //确保nums[d] 改变了
d--;
}
d--;
}
}
}
}
return result;
}
}
比起三数之和就是外面多了一个循环。
三数之和的关键是去重。如何避免重复结果。使用排序数组加双指针。当前数字和前一个数字比较
四数之和就是在三数之和的基础上,外面再套了一个 for 循环。
一看啥都会,自己写啥也不会。。。