15.三数之和
解题思路:
package leadcode;
import java.util.*;
/**
* @author : icehill
* @description : 三数之和
* 给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,
* 使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
* 注意:答案中不可以包含重复的三元组。
* 示例 1:
* 输入:nums = [-1,0,1,2,-1,-4]
* 输出:[[-1,-1,2],[-1,0,1]]
* 示例 2:
* 输入:nums = []
* 输出:[]
* 示例 3:
* 输入:nums = [0]
* 输出:[]
* 来源:力扣(LeetCode)
* 链接:https://leetcode-cn.com/problems/3sum
* 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
* 1.使用哈希表+双重循环
* 时间复杂度:O(n^2) 空间复杂度:O(n)
* 2.排序+双指针
* 时间复杂度:O(n^2) 空间复杂度:O(1)
* @date : 2021-05-04
*/
public class Solution15 {
public static void main(String[] args) {
Solution15 solution15 = new Solution15();
int[] nums = {};
solution15.threeSum(nums);
}
/**
* 哈希表+双循环
* @param nums
* @return
*/
public List<List<Integer>> threeSum(int[] nums) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
if (map.get(nums[i]) == null) {
map.put(nums[i], 1);
} else {
map.put(nums[i], map.get(nums[i]) + 1);
}
}
List<List<Integer>> list = new ArrayList<>();
Map<String, Boolean> existsMap = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
for (int j = i + 1; j < nums.length; j++) {
int thirdNum = 0 - nums[i] - nums[j];
Integer temp = map.get(thirdNum);
if (temp != null) {
int count = 1;
if (thirdNum == nums[i]) {
count++;
}
if (thirdNum == nums[j]) {
count++;
}
if (temp < count) {
continue;
}
List<Integer> subList = sort(nums[i], nums[j], thirdNum);
String key = subList.get(0) + "#" + subList.get(1) + "#" + subList.get(2);
if (existsMap.get(key) == null) {
list.add(subList);
existsMap.put(key, true);
}
}
}
}
return list;
}
/**
* 排序
*
* @param a
* @param b
* @param c
* @return
*/
private List<Integer> sort(int a, int b, int c) {
List<Integer> subList = new ArrayList<>();
if (a < b) {
int t = a;
a = b;
b = t;
}
if (a < c) {
int t = a;
a = c;
c = t;
}
if (b < c) {
int t = b;
b = c;
c = t;
}
subList.add(c);
subList.add(b);
subList.add(a);
return subList;
}
/**
* 排序+双指针(处理重复)
* @param nums
* @return
*/
public List<List<Integer>> threeSumTwo(int[] nums) {
int n = nums.length;
Arrays.sort(nums);
List<List<Integer>> ans = new ArrayList<>();
// 枚举 a
for (int first = 0; first < n; ++first) {
// 需要和上一次枚举的数不相同
if (first > 0 && nums[first] == nums[first - 1]) {
continue;
}
// c 对应的指针初始指向数组的最右端
int third = n - 1;
int target = -nums[first];
// 枚举 b
for (int second = first + 1; second < n; ++second) {
// 需要和上一次枚举的数不相同
if (second > first + 1 && nums[second] == nums[second - 1]) {
continue;
}
// 需要保证 b 的指针在 c 的指针的左侧
while (second < third && nums[second] + nums[third] > target) {
--third;
}
// 如果指针重合,随着 b 后续的增加
// 就不会有满足 a+b+c=0 并且 b<c 的 c 了,可以退出循环
if (second == third) {
break;
}
if (nums[second] + nums[third] == target) {
List<Integer> list = new ArrayList<Integer>();
list.add(nums[first]);
list.add(nums[second]);
list.add(nums[third]);
ans.add(list);
}
}
}
return ans;
}
}