四数之和
给一个包含n个数的整数数组S,在S中找到所有使得和为给定整数target的四元组(a, b, c, d)。
注意事项
四元组(a, b, c, d)中,需要满足a <= b <= c <= d
答案中不可以包含重复的四元组。
例如,对于给定的整数数组S=[1, 0, -1, 0, -2, 2] 和 target=0. 满足要求的四元组集合为:
(-1, 0, 0, 1)
(-2, -1, 1, 2)
(-2, 0, 0, 2)
这是一道数组求和的问题,看了网上很多解答的算法,比较流行的是一个先排序,然后选两个数字,接着后面用两个指针分别指向剩下数组开始和结束,逐步移向中间求和看和targer是否相等,但是这样的算法感觉实现起来太不优雅了。想到一个深度遍历的算法,可以到达同样的效果,而且以后无论多少个数求和,都能解决。代码如下:
public ArrayList<ArrayList<Integer>> fourSum(int[] numbers, int target) {
Arrays.sort(numbers);
ArrayList<ArrayList<Integer>> ret = new ArrayList<>();
dfs(ret, new ArrayList<Integer>(), numbers, 0, target);
return ret;
}
private void dfs(ArrayList<ArrayList<Integer>> ret, ArrayList<Integer> condidate, int[] numbers, int curIndex,
int target) {
// 以后求n数和,只要改这里就能解决,比如4改为3,改为5
if (condidate.size() == 4) {
int total = getSum(condidate);
if (total == target) {
ret.add(new ArrayList<>(condidate));
}
return;
}
if (curIndex > numbers.length - 1) {
return;
}
for (int i = curIndex; i < numbers.length; i++) {
// 如果是一样的数字,直接忽略,否则会有重复的答案
if (i != curIndex && numbers[i] == numbers[i - 1]) {
continue;
}
condidate.add(numbers[i]);
// 如果已经大于target,并且当前数字大于0,再循环加下去已经没有意义了,因为只会更大,直接return
if (getSum(condidate) > target && numbers[i] > 0) {
if (!condidate.isEmpty()) {
condidate.remove(condidate.size() - 1);
}
return;
}
dfs(ret, condidate, numbers, i + 1, target);
if (!condidate.isEmpty()) {
condidate.remove(condidate.size() - 1);
}
}
}
private int getSum(ArrayList<Integer> condidate) {
int total = 0;
for (Integer num : condidate) {
total += num;
}
return total;
}