LeetCode15.给你一个包含n个整数的数组 nums,判断 nums 中是否存在三个元素a,b,c,使得 a+b+c=0?请你找出所有和为0且不重复的三元组。注意:答案中不可以包含重复的三元组。
示例1:
输入:nums=[-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]
public List<List<Integer>> threeSum(int[] nums) {
int n = nums.length;
Arrays.sort(nums);
List<List<Integer>> ans = new ArrayList<List<Integer>>();
// 枚举 a
for (int first = 0; first < n; ++first) {
// 需要和上一次枚举的数不相同
if (first > 0 && nums[first] == nums[first - 1]) {
continue;
}
// c 对应的指针初始指向数组的最右端
int third = n - 1;
int target = -nums[first];
// 枚举 b
for (int second = first + 1; second < n; ++second) {
// 需要和上一次枚举的数不相同
if (second > first + 1 && nums[second] == nums[second - 1]) {
continue;
}
// 需要保证 b 的指针在 c 的指针的左侧
while (second < third && nnums[second] + nums[third] > target) {
--third;
}
// 如果指针重合,随着 b 后续的增加
// 就不会有满足 a+b+c=0 并且 b<c 的 c 了,可以退出循环
if (second == third) {
break;
}
if (nums[second] + nums[third] == target) {
List<Integer> list = new ArrayList<Integer>();
list.add(nums[first]);
list.add(nums[second]);
list.add(nums[third]);
ans.add(list);
}
}
}
return ans;
}
首先,代码对数组进行排序,这样可以方便地在后面使用双指针来寻找符合条件的数。
然后,代码使用两个嵌套的循环来枚举所有可能的三元组。外层循环枚举第一个数,内层循环枚举第二个数。为了避免重复计算,内层循环从外层循环下标的下一个位置开始枚举。同时,为了避免重复解,内层循环在枚举第二个数时,需要保证它和上一个枚举的数不相同。
在内层循环中,代码使用双指针来找到第三个数。第三个数的值等于目标值减去前两个数的和的相反数。初始时第三个数的指针指向数组的最右端。为了找到所有符合条件的三元组,代码需要不断地移动第二个数和第三个数的指针。如果它们的和大于目标值,则需要将第三个数的指针左移;如果它们的和小于目标值,则需要将第二个数的指针右移。
最后,如果找到符合条件的三元组,则将它们加入到结果列表中,并继续寻找下一个符合条件的三元组。如果第二个数和第三个数的指针相遇,则退出内层循环,继续枚举下一个第一个数。最终返回所有符合条件的三元组的列表。