题目描述
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
- 示例:
给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]题解
自解(三循环)(超时)
很直观地想到运用到三个循环,将每个三数组合都遍历一遍,然后取出和为0的一组数据,但是提交之后出现了超时。超时的原因有两个,一是用到三个循环,需要很长的遍历时间;二是需要去重,要额外创建一个集合。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> res = new ArrayList<>();
int len = nums.length;
if (len == 0)
return res;
Set<List<Integer>> set = new HashSet<>();
for (int i = 0; i < len - 2; i++) {
for (int j = i+1; j < len - 1; j++) {
int k = j +1;
while (k < len) {
List<Integer> tempt = new ArrayList<>(Arrays.asList(nums[i], nums[j], nums[k]));
if (nums[i] + nums[j] + nums[k] ==0 && !set.contains(tempt)) {
res.add(tempt);
set.add(tempt);
}
k++;
}
}
}
return res;
}
双指针
结合之前做过的四数的之和的题目,运用双指针的方法,就可以做到既减少遍历次数,又避免去重过程。
使用双指针方法需要注意的点有:
- 对于遍历的第一个数当该数大于0,则三数之和一定大于零,因为是自然顺序排列的
- 当遇到相同的数,直接滑动指针去重。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36public List<List<Integer>> threeSum(int[] nums) {
int len = nums.length;
List<List<Integer>> res = new ArrayList<>();
if (len == 0)
return res;
Arrays.sort(nums);
for (int i = 0; i < len - 2; i++) {
int max = nums[i] + nums[len - 2] + nums[len - 1];
int min = nums[i] + nums[i + 1] + nums[i + 2];
if (max < 0 || min > 0)
continue;
if (i > 0 && nums[i] == nums[i-1])
continue;
int j = i + 1;
int k = len - 1;
while (j < k) {
int temp = nums[i] + nums[j] + nums[k];
if (temp < 0) {
j++;
}else if (temp > 0) {
k--;
}else {
res.add(Arrays.asList(nums[i], nums[j], nums[k]));
while (j<k && nums[j] == nums[j+1]) {
j++;
}
j++;
while (j<k && nums[k] == nums[k-1]) {
k--;
}
k--;
}
}
}
return res;
}