一、题意
给定一个包含 n 个整数的数组 S,是否存在属于 S 的三个元素 a,b,c 使得 a + b + c = 0 ?找出所有不重复的三个元素组合使三个数的和为零。
注意:结果不能包括重复的三个数的组合。
例如, 给定数组 S = [-1, 0, 1, 2, -1, -4],
一个结果集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
第一种解法(超时)双指针法
思路:
class Solution{
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
if (nums.length < 3) return res;
Arrays.sort(nums);
final int target = 0;
for (int i = 0; i < nums.length - 2; ++i) {
if(i > 0 && nums[i] == nums[i-1]){//写个具体的例子,为了减小复杂度
continue;
}
int j = i+1;
int k = nums.length-1;
while(j < k){
int sum = nums[i] + nums[j] + nums[k];
if(sum < 0){
j++;
}else if(sum > 0){
k--;
}else{
List<Integer> list = new ArrayList<>();
list.add(nums[i]);
list.add(nums[j]);
list.add(nums[k]);
if(!res.contains(list)){
res.add(list);
}
}
}
}
return res;
}
}
超时的原因是:对是否有重复的判断使用了
if(!res.contains(list)){
res.add(list);
}
使用它的话,
第二种解法(未超时)重新写了判断重复的方法
- 这里用到了三个指针i,j,k。i从第一个数到倒数第三个数依次遍历,初始化时j指向i后面一个数,k指向最后一个数。判断i,j,k位置上的数和0的关系,如果大于0,则k–,如果小于0,则j++。
- 题目中要求不能有重复的数字出现,这里举几个例子。
- -6,-3,-3,-3,-3,0,1,2,2,3,3,在这个例子中,当i走到-3这里时,会出现很多重复的现象,所以就有了
if(i > 0 && nums[i] == nums[i-1]){ //如果上一个i位置的数和当前i位置的数相同,则跳到下一次循环 continue; }
同理j的位置和k的位置出现相同的数字也会有很多重复现象的发生
class Solution{
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
if (nums.length < 3) return res;
Arrays.sort(nums);
final int target = 0;
for (int i = 0; i < nums.length - 2; ++i) {
if(i > 0 && nums[i] == nums[i-1]){//在博客里写个具体的例子,为了减小复杂度
continue;
}
int j = i+1;
int k = nums.length-1;
while(j < k){
int sum = nums[i] + nums[j] + nums[k];
if(sum < 0){
j++;
while(nums[j] == nums[j-1] && j < k) ++j;
}else if(sum > 0){
k--;
while(nums[k] == nums[k+1] && j < k) --k;
}else{
List<Integer> list = new ArrayList<>();
list.add(nums[i]);
list.add(nums[j]);
list.add(nums[k]);
res.add(list);
++j;
--k;
while(nums[j] == nums[j-1] && j < k) ++j;
while(nums[k] == nums[k+1] && j < k) --k;
}
}
}
return res;
}
}
###转为两数之和来解