LeetCode第15题
/*
Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
Note:
The solution set must not contain duplicate triplets.
Example:
Given array nums = [-1, 0, 1, 2, -1, -4],
A solution set is:
[
[-1, 0, 1],
[-1, -1, 2]
]
*/
import java.util.*;
public class ThreeSum{
public static void main(String[] args){
int[] nums = {-6,-6,-5,2,3,3,5,6,5,11,12,13,14};
ThreeSum ts = new ThreeSum();
List<List<Integer>> result = ts.threeSum02(nums);
System.out.println(result);
}
// 排序之后,我们就可以对数组用两个指针分别从前后两端向中间扫描了,
// 如果是 2Sum,我们找到两个指针之和为target就OK了,那 3Sum 类似,
// 我们可以先固定一个数,然后找另外两个数之和为第一个数的相反数就可以了。
// 要记得我们的 nums 已经有序了,所以只需要找到一组之后,当前指针要移到和当前元素不同的地方。
// 其次在遍历数组的时候,如果和上个数字相同,也要继续后移。
public List<List<Integer>> threeSum02(int[] nums) {
// List的链表实现,增加元素快,查询慢
List<List<Integer>> res = new LinkedList<>();
if (nums == null || nums.length < 3) return res;
//Collections.sort是对容器排序
Arrays.sort(nums);
// System.out.println(Arrays.toString(nums));
for(int i=0;i<nums.length;i++){
// -6,-6,-5,2,3,3,5,6,5,11,12,13,14 第一个解为{-6,-6,12},
// 若从第二个-6开始,只能找到比-6大的或相等的数一起作为解
// 如果可以再找一个-6,解就是重复解,找一个比-6大的数做解也是重复解(前一个-6已经校验过了)
// -6,-6,-5,2,3,3,5,6,5,11 第一个解为{-6,-5,11},
// 若从第二个-6开始,只能找到比-6大的作为解
// 再找一个-5,解就是重复解(前一个-6已经校验过了)
// -6,-6,-5,2,3 没有解
// 若从第二个-6开始,同样没有解
if(i > 0 && nums[i-1]==nums[i]) continue;
// 每次的begin不同,end相同
int begin = i+1,end = nums.length - 1;
while(begin < end){
if (nums[i] + nums[begin] + nums[end] == 0){
// 原来Arrays.asList可以将多个元素直接变List
res.add(Arrays.asList(nums[i], nums[begin], nums[end]));
//元素相同要后移,防止加入重复的 list,移动到最后一个和当前数相等的位置
while (begin < end && nums[begin] == nums[begin+1]) begin++;
while (begin < end && nums[end] == nums[end-1]) end--;
// 移动到第一个不相同的元素
// 若begin加,而end不减,end也不可能再次作为解的一部分
begin++;end--;
}else{
if(nums[i] + nums[begin] + nums[end] < 0){
// 说明nums[begin] + nums[end]之和不够大,最大begin
begin++;
}else{
// 说明nums[begin] + nums[end]之和不够小,减小end
end--;
}
}
}
}
return res;
}
// 暴力破解
public List<List<Integer>> threeSum01(int[] nums) {
// 存储所有的解
List<List<Integer>> solutions = new ArrayList<>();
// 输入检查
if (nums == null || nums.length < 3) return solutions;
int numsLen = nums.length;
// 存储解的排序后字符串,用于排除冗余解
HashSet<String> sites = new HashSet<String>();
for(int i = 0;i<numsLen;i++){
for(int j = i+1;j<numsLen;j++){
for(int k=j+1;k<numsLen;k++){
int sum = nums[i] + nums[j] + nums[k];
if (sum == 0){
List<Integer> solution = new ArrayList<>();
solution.add(nums[i]);solution.add(nums[j]);solution.add(nums[k]);
// 对解进行自我排序
Collections.sort(solution);
if (!sites.contains(solution.toString())){
// 将未加入的解加入解容器
sites.add(solution.toString());
solutions.add(solution);
}
}
}
}
}
return solutions;
}
}