题目
链接:https://leetcode.cn/problems/1fGaJU
给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a ,b ,c ,使得 a + b + c = 0 ?请找出所有和为 0 且 不重复 的三元组。
思路
007属于006的进阶题。
实际上是在两个数加和的基础上,又多了一层。
那我们可以先固定第一个元素a,之后另外两个元素按照006题的方式找到两数和为-a的元素,就好了。
所以我们首先要做的,是对数组进行一次排序,然后从小到大开始,先指定第一个元素,之后从它右边的元素中,用双指针方法找到符合条件的两个元素。
这里要注意几点:
- 所有和为0。所以不像上次,找到结果就返回。需要两个指针汇合,才能完成遍历。
- 不重复。这个可以用一个set去重,也可以在遍历的过程中,跳过重复的数据。
解法一:set去重
逻辑
- 先对数组排序,不要吝啬使用自带的API
- 从左往右遍历,确定第一个元素后,用双指针法找到后两个元素
- 将组合放入set中
- 返回结果
代码
public List<List<Integer>> threeSum(int[] nums) {
Set<List<Integer>> resultList = new HashSet<>();
Arrays.sort(nums);
for (int i = 0; i < nums.length; i++) {
int target = -nums[i];
if (target < 0) {
break;
}
int leftIndex = i + 1;
int rightIndex = nums.length - 1;
while (leftIndex < rightIndex) {
int sum = nums[leftIndex] + nums[rightIndex];
if (sum == target) {
resultList.add(Arrays.asList(nums[i], nums[leftIndex], nums[rightIndex]));
leftIndex++;
} else if (sum > target) {
rightIndex--;
} else {
leftIndex++;
}
}
}
return new ArrayList<>(resultList);
}
解法二:遍历过程中去重
逻辑
和上一个解法不同的是,我们在遍历的过程中,自动跳过重复的元素。这样比用一个set维护,效率更高一些。
代码
public List<List<Integer>> threeSum2(int[] nums) {
List<List<Integer>> resultList = new ArrayList<>();
Arrays.sort(nums);
for (int i = 0; i < nums.length; i++) {
// 最小的元素都大于0了,那肯定不用看后面的了
if (nums[i] > 0) {
break;
}
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
int leftIndex = i + 1;
int rightIndex = nums.length - 1;
while (leftIndex < rightIndex) {
int sum = nums[i] + nums[leftIndex] + nums[rightIndex];
if (sum == 0) {
resultList.add(Arrays.asList(nums[i], nums[leftIndex], nums[rightIndex]));
leftIndex++;
while (leftIndex < rightIndex && nums[leftIndex] == nums[leftIndex - 1]) {
leftIndex++;
}
} else if (sum > 0) {
rightIndex--;
} else {
leftIndex++;
}
}
}
return resultList;
}