三数之和
题目要求
给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
例子
例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:[ [-1, 0, 1],[-1, -1, 2] ]
解题思路
1.首先想到的最简单最傻的做法是三层循环,时间复杂度为O(n的三次方)不建议使用,只是一个思路而已。
2.阅读题目,三个要求:三个元素,且和为0,不重复三元组。大概只能从和为0下手。排除三个都为0的情况,那么必有一个负数存在。所以我们先排下序。
3.我们只需要遍历前面的负数和0,也就是>0的我们统统不要了。我们需要拿到第一个负数。
Arrays.sort(nums);
for (int i = 0; i < nums.length; i++) {
if (nums[i] > 0) break;
4.拿到第一个负数后,我们只需要再拿到后面两个数,与之相加=0即可。后面两个数我们用两个指针来表示,j和k,一个是从左边往右边走,一个是从最右边往前走。有些思想就是想通的,之前的两数之和就是这种思路。先排好序,左边一个left指针,右边一个right指针,如果left+right > result,那么right往左移,如果left+right < result,那么说明相加得数不够,就需要left往右移。找到相加之和相等的就行。此题,也是如此。
int target = 0 - nums[i];
int k = i + 1;
while (k < j) {
if (nums[k] + nums[j] == target) {
5.不过在这里要注意一个问题,就是题目中提到的“答案中不可以包含重复的三元组”,所以我们需要把相同的数字过滤掉。
其实很简单,只需要往下或者往前走一位,其他什么都不要做。
while (k < j && nums[k] == nums[k + 1]) k++;
while (k < j && nums[j] == nums[j - 1]) j--;
完整代码
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
Arrays.sort(nums);
for (int i = 0; i < nums.length; i++) {
if (nums[i] > 0) break;
if (i > 0 && nums[i] == nums[i - 1]) continue;
int j = nums.length - 1;
int target = 0 - nums[i];
int k = i + 1;
while (k < j) {
if (nums[k] + nums[j] == target) {
List<Integer> item = Arrays.asList(nums[i], nums[k], nums[j]);
result.add(item);
while (k < j && nums[k] == nums[k + 1]) k++;
while (k < j && nums[j] == nums[j - 1]) j--;
k++;j--;
} else if (nums[k] + nums[j] < target) {
k++;
} else {
j--;
}
}
}
return result;
}
}