题目描述:

给你一个包含 ​​n​​​ 个整数的数组 ​​nums​​​ ,判断 ​​nums​​ 中是否存在三个元素 abc ,使得 a + b + c = 0 ? 请你找出所有和为 ​​0​​ 且不重复的三元组。

注意: 答案中不可以包含重复的三元组。

示例 1:

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]

示例 2:

输入:nums = []
输出:[]

示例 3:

输入:nums = [0]
输出:[]

提示:

  • 0 <= nums.length <= 3000
  • - <= nums[i] <=

题目分析:

这道题可以通过双指针的方法解决。开始先判断长度是否至少有三个数,没有三个数就直接返回空列表。长度满足要求再对数组进行排序,然后遍历这个数组,固定第一个数,让左指针指向该固定数的下一个数,而让右指针指向数组最后一个数,计数三者之和,满足条件则加入列表。添加完后需要用两个循环判断左指针指向的下一个数是否与当前左指针指向的数相同,如果相同直接跳过下一个数,这么做是为了去重。右指针同理。如果三者之和小于零,则需要更大的数才有可能使和变为零,当前已经固定了一个数,要使和变大,就要移动左指针。右指针同理。

题解:

执行用时: 20 ms

内存消耗: 42.1 MB

class Solution {
public List<List<Integer>> threeSum(int[] nums) {
// 获取长度
int length = nums.length;
// 当 数组为空 或者 长度小于三
if (nums == null || length < 3) {
// 直接返回一个空列表
return new ArrayList<>();
}
// 创建 ArrayList
List<List<Integer>> list = new ArrayList();
// 对数组进行排序
Arrays.sort(nums);
// 遍历数组
for (int i = 0; i < length; ++i) {
// 如果当前数字大于 0 ,则与后面任何数进行组合三者之和都会大于 0
if (nums[i] > 0) {
// 直接退出
break;
}
// 如果 i > 0 且该数与前面一个数一致,跳过此次循环,相当于去重
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
// 左指针索引 初始值为 i + 1
int left = i + 1;
// 右指针索引 初始值为数组长度减一
int right = length - 1;
// 左索引小于右索引循环
while(left < right) {
// 求当前数与左索引上的值与右索引上的值三者之和
int sum = nums[i] + nums[left] + nums[right];
// 如果和为 0 符合要求
if(sum == 0) {
// 将其添加至列表
list.add(Arrays.asList(nums[i], nums[left], nums[right]));
// 以下循环为了去重
while (left < right && nums[left] == nums[left + 1]) {
++left;
}
while (left < right && nums[right] == nums[right - 1]) {
--right;
}
// 左索引加一
++left;
// 右索引减一
--right;
} else if (sum < 0) {
// 如果和小于 0 需要让和更大 左索引加一
++left;
} else if (sum > 0) {
// 如果和大于 0 需要让和更小 右索引减一
--right;
}
}
}
// 返回 list
return list;
}
}

题目来源:力扣(LeetCode)