题目
给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
算法1
public class P15_3Sum {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> rlist = new ArrayList<>();
Map<String,String> map = new HashMap<>();
for(int i=0;i<nums.length-2;i++){
for(int j=i+1;j<nums.length-1;j++){
for(int k=j+1;k<nums.length;k++){
if(nums[i]+nums[j]+nums[k]==0){
int[] array = {nums[i],nums[j],nums[k]};
Arrays.sort(array);
if(map.get(array[0]+","+array[1])==null||map.get(array[0]+","+array[1]).equals("")){
map.put(array[0]+","+array[1],"1");
List<Integer> l = new ArrayList<>();
l.add(nums[i]);
l.add(nums[j]);
l.add(nums[k]);
rlist.add(l);
}else {
continue;
}
}
}
}
}
return rlist;
}
}
思路:这个是我首先想到的暴力解法,三层循环遍历所有可能的三元组情况,再使用Hashmap去重。(方法超时)
算法2
public class P15_3Sum2 {
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> ls = new ArrayList<>();
for (int i = 0; i < nums.length - 2; i++) {
if (i == 0 || (i > 0 && nums[i] != nums[i - 1])) { // 跳过可能重复的答案
int l = i + 1, r = nums.length - 1, sum = 0 - nums[i];
while (l < r) {
if (nums[l] + nums[r] == sum) {
ls.add(Arrays.asList(nums[i], nums[l], nums[r]));
while (l < r && nums[l] == nums[l + 1]) l++;
while (l < r && nums[r] == nums[r - 1]) r--;
l++;
r--;
} else if (nums[l] + nums[r] < sum) {
while (l < r && nums[l] == nums[l + 1]) l++; // 跳过重复值
l++;
} else {
while (l < r && nums[r] == nums[r - 1]) r--;
r--;
}
}
}
}
return ls;
}
}
思路:先对数组排序,再将num1+num2+num3=0转换成num2+num3=0-num1来做。
这里求两数之和用到了左右指针法,其中左指针指向num2,右指针指向num3.
因为数组是有序的,所以要使num2+num3和一定,
- 连续相等的情况,只移动其中一边的指针
- 其余情况需要向内移动左右指针。