/**
* @Class ThreeSum
* @Description
* 给你一个包含 n 个整数的数组 nums,
* 判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?
* 请你找出所有满足条件且不重复的三元组。
*
* 注意:答案中不可以包含重复的三元组。
*
* 给定数组 nums = [-1, 0, 1, 2, -1, -4],
*
* 满足要求的三元组集合为:
* [
* [-1, 0, 1],
* [-1, -1, 2]
* ]
*
* @Author 10256137
* @Date 2020/6/12
**/
public class ThreeSum {
}
/**
* 解法2:穷举法,利用排序去重,再逐个穷举
* 时间复杂度:O(n^3)
* 空间复杂度:O(n)
*/
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
if(nums== null || nums.length==0){
return new ArrayList<>();
}
List<List<Integer>> res = new ArrayList<>();
for (int i = 0; i < nums.length; i++) {
if(i>0 && nums[i]== nums[i-1]) continue; // 去重
for (int j = i+1; j <nums.length ; j++) {
if(j>i+1 && nums[j]== nums[j-1]) continue;
for (int k = j+1; k < nums.length; k++) {
if(k>j+1 && nums[k] == nums[k-1]) continue;
if(nums[i] + nums[j] + nums[k] == 0){
List<Integer> integers = new ArrayList<>();
integers.add(nums[i]);
integers.add(nums[j]);
integers.add(nums[k]);
res.add(integers);
}
}
}
}
return res;
}
/**
* 解法2:先排序,目的是为了去重,
* 利用键值记录可以直接判断第三个数是否已存在,这样的话就不需要再对剩余的数据逐个判断,少了一个计算量级
* 时间复杂度:O(n^2)
* 空间复杂度:O(n)
*/
public List<List<Integer>> threeSum(int[] nums) {
if(nums== null || nums.length==0){
return new ArrayList<>();
}
Arrays.sort(nums);
Map<Integer,Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
map.put(nums[i], i);
}
List<List<Integer>> res = new ArrayList<>();
for (int i = 0; i < nums.length; i++) {
if(i>0 && nums[i]== nums[i-1]) continue; // 排序后对比是为了去重
for (int j = i+1; j <nums.length ; j++) {
if(j>i+1 && nums[j]== nums[j-1]) continue;
int a = nums[i];
int b = nums[j];
int c = -a-b;
if(map.containsKey(c) && map.get(c) > j){ // > j目的是去重
List<Integer> integers = new ArrayList<>();
integers.add(a);
integers.add(b);
integers.add(c);
res.add(integers);
}
}
}
return res;
}
/**
* 解法3: 先对元素进行排序(快排)固定某元素num[i],在其后面的一组元素中从两端选择两个元素,
* 如果元素num[i]大于0,则其后的所有元素都>0,不可能存在一组3个元素之和等于0
* 如果num[i]和选择的两个元素num[L],num[R] 之和小于0,则L++
* 如果num[i]和选择的两个元素num[L],num[R] 之和大于0,则R--
*/
public List<List<Integer>> threeSum(int[] nums) {
if(nums== null || nums.length==0){
return new ArrayList<>();
}
// 底层用的快排
Arrays.sort(nums);
Map<Integer,Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
map.put(nums[i], i);
}
List<List<Integer>> res = new ArrayList<>();
int len = nums.length;
for (int i = 0; i < len; i++) {
if(nums[i]>0) break;
if((i>0) && (nums[i]== nums[i-1])) continue; // 去重
int L = i+1,R = len-1;
while (L < R){
int count = nums[i] + nums[L] + nums[R];
if(count == 0){
List<Integer> integers = new ArrayList<>();
integers.add(nums[i]);
integers.add(nums[L]);
integers.add(nums[R]);
res.add(integers);
// 去重复
while (L < R && nums[L] == nums[L + 1]) L++;
while (L < R && nums[R] == nums[R - 1]) R--;
L++;
R--;
}
if(count < 0) L++;
if(count > 0) R--;
}
}
return res;
}