其实这道题类似于力扣的40题组合的题目。
https://blog.csdn.net/qq_63748940/article/details/134979657?spm=1001.2014.3001.5501
给定了一个数组,先排好序:nums = [ -4, -1, -1, 0, 1, 2], 题目要求返回所有和为0且不重复的三元组。
这道题可以用之前两数之和的解法。三数之和,我们可以先固定一个数,比如先固定 - 4,那么接下来我们要找的两个数之和等于 4 就行了,看看能不能找到解,若找到解了,先把存储在栈中的元素放入集合,然后再向集合中加入其它满足要求的元素;若不能找到解,则固定其他的数。固定 -1, 0,1,2(数组中重复的元素不用再次固定)
注意:运用之前两数之和的解法需要数组先排好序。
此图中已经固定了 - 4,接下来找剩下两数之和等于target = 4 就可以了。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
public class SumLeetcode15 {
public static List> threeSum(int[] nums) {
List> result = new ArrayList<>();
Arrays.sort(nums);
dfs(3, 0, nums.length - 1, 0, nums, new LinkedList<>(), result);
return result;
}
/**
* @param n 一共有n个数,n数之和
* @param i 固定好一个元素后,该元素右边的一个数的索引
* @param j 数组最右侧的元素
* @param target 目标元素
* @param nums 原始数组
* @param stack 把固定的元素存入栈中
* @param result 用于返回的大集合
*/
public static void dfs(int n, int i, int j, int target, int[] nums,
LinkedList stack, List> result) {
if (n == 2) { //剩下两个数
twoSum(i, j, nums, target, stack, result);
return;
}
//先固定一个数
for (int k = i; k < j - (n - 2); k++) {
//检查是否重复固定
if (k > i && nums[k] == nums[k - 1]) {
continue;
}
//固定一个数字,再尝试 n - 1 数字之和
stack.push(nums[k]);
dfs(n - 1, k + 1, j, target - nums[k], nums, stack, result);
stack.pop();
}
}
public static void twoSum(int i, int j, int[] numbers, int target,
LinkedList stack, List> result) {
while (i < j) {
int sum = numbers[i] + numbers[j];
if (sum < target) {
i++;
} else if (target < sum) {
j--;
} else { //找到了
List list = new ArrayList<>(stack); //把固定的元素加入集合中
list.add(numbers[i]);
list.add(numbers[j]);
result.add(list);
//缩小范围找其它解
i++;
j--;
while (i < j && numbers[i] == numbers[i - 1]) {
i++;
}
while (i < j && numbers[j] == numbers[j + 1]) {
j--;
}
}
}
}
public static void main(String[] args) {
//int[] candidates = {-4, -1, -1, 0, 0, 1, 1, 2}; //[-1,0,1,2,-1,-4]
int[] candidates = {-1, 0, 1, 2, -1, -4};
System.out.println(threeSum(candidates));
}
}