1.题目描述:给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
2.方法一,暴力求解:
package algorithm;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.InputMismatchException;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
public class ThreeSum2 {
public static void main(String args[]) {
int temp,target;
ArrayList arraylist = new ArrayList();
Scanner reader = new Scanner(System.in);
System.out.println("请输入一个数组,按回车键结束:");
String s = reader.nextLine();
Scanner reader2 = new Scanner(s);
//以下将字符转换回整数存入数组(将数字抽取出来)
while(reader2.hasNext()) {
try {
int num=reader2.nextInt();
arraylist.add(num);
}catch(InputMismatchException exp) {
String t=reader2.next();
}
}
//将arraylist转换为int[]型数组,以便和参数相对应;
int [] intArray = new int[arraylist.size()];
for(int i=0;i<arraylist.size();i++) {
intArray[i]=(int) arraylist.get(i);
}
List<List<Integer>> result = new ArrayList<>();
Solution obj = new Solution();
result = obj.threeSum(intArray);
System.out.println("返回结果:");
System.out.println("[ ");
/*
* 重新构造一个int[]数组,用toString进行输出;构造过程跟上面将arraylist转换int[]数组一样,for循环;
*/
int [] array;
for (int i = 0; i < result.size(); i++) {
array = new int[result.get(i).size()];
for (int j = 0; j < result.get(i).size(); j++) {
array[j] = (int) result.get(i).get(j);
}
if (i != result.get(i).size() - 1) {
System.out.println(Arrays.toString(array) + ',');
} else {
System.out.println(Arrays.toString(array));
}
}
System.out.println(" ]");
}
}
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
int n=0;
List<List<Integer>> list2 = new ArrayList<>();
for(int i=0;i<nums.length;i++) {
for(int j=0;j<nums.length;j++) {
if(j==i) {
continue;
}
for(int k=0;k<nums.length;k++) {
if(k==i||k==j) {
continue;
}
if (nums[i] + nums[j] + nums[k] == 0) {
List<Integer> list1 = new LinkedList<>();
list1.add(nums[i]);
list1.add(nums[j]);
list1.add(nums[k]);
Collections.sort(list1);
if (!list2.contains(list1)) {
list2.add(list1);
}
}
}
}
}
return list2;
}
}
执行结果如下:

方法二:使用hashmap,时间复杂度O(n2):
package algorithm;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.InputMismatchException;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
public class ThreeSum4 {
public static void main(String args[]) {
int temp,target;
ArrayList arraylist = new ArrayList();
Scanner reader = new Scanner(System.in);
System.out.println("请输入一个数组,按回车键结束:");
String s = reader.nextLine();
Scanner reader2 = new Scanner(s);
//以下将字符转换回整数存入数组(将数字抽取出来)
while(reader2.hasNext()) {
try {
int num=reader2.nextInt();
arraylist.add(num);
}catch(InputMismatchException exp) {
String t=reader2.next();
}
}
//将arraylist转换为int[]型数组,以便和参数相对应;
int [] intArray = new int[arraylist.size()];
for(int i=0;i<arraylist.size();i++) {
intArray[i]=(int) arraylist.get(i);
}
List<List<Integer>> result = new ArrayList<>();
Solution obj = new Solution();
result = obj.threeSum(intArray);
System.out.println("返回结果:");
System.out.println('[');
/*
* 重新构造一个int[]数组,用toString进行输出;构造过程跟上面将arraylist转换int[]数组一样,for循环;
*/
int [] array;
for (int i = 0; i < result.size(); i++) {
array = new int[result.get(i).size()];
for (int j = 0; j < result.get(i).size(); j++) {
array[j] = (int) result.get(i).get(j);
}
if (i != result.get(i).size() - 1) {
System.out.println(Arrays.toString(array) + ',');
} else {
System.out.println(Arrays.toString(array));
}
}
System.out.println(']');
}
}
class Solution{
public List<List<Integer>> threeSum(int[] nums) {
Integer comp;
Map<Integer,Integer> map = new HashMap<>();
Map<List,Integer> map2 = new HashMap<>();
List<List<Integer>> list2 = new ArrayList<>();
//将数组每个元素出现的个数以键值对的形式记录在map
for(int i=0;i<nums.length;i++) {
Integer num = map.get(nums[i]);
map.put(nums[i], num==null? 1: num+1);
}
Arrays.sort(nums);
for(int i=0;i<nums.length-1;i++) {
for (int j = i + 1; j < nums.length-1; j++) {
int complement = -nums[i] - nums[j];
comp = Integer.valueOf(complement);
if(map.containsKey(comp)) {
if(complement==nums[i]||complement==nums[j]) {
//如果是0,必须出现3个以上
if(complement==0) {
if(map.get(comp).intValue()<3) {
continue;
}
}else {
if(map.get(comp).intValue()<2) {
continue;
}
}
}
List<Integer> list1 = new ArrayList<>();
list1.add(nums[i]);
list1.add(nums[j]);
list1.add(complement);
Collections.sort(list1);//[-1,1]和[1,-1]是不一样的,所以需排序使它们一样,便于后面排除,解决了三元组重复问题
if (!list2.contains(list1)) {
list2.add(list1);
}
}
}
}
return list2;
}
}
测试结果:


以上两种方法有弊端,方法一太不值得提倡了,O(n3)的时间复杂度基本可以丢弃了,方法二的话虽说压缩到O(n2),但当遇到有许多重复元素的数组时,不能去除不必要的运算。且方法二leetcode上还有2个例子没跑过,超出时间限制。下面贴出可以在leetcode上跑过的代码,别人的答案:
class Solution {
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;
}
}
有点类似于快速排序算法吧,自己对快速排序不是很了解,没想到这种方法。
后记:这道题也折腾了好几天,当然是断断续续,主要是对java的map,list,set,hashcode等理解不深,用的过程出了很多错误,不过通过这道题也对这些容器的用法也有所了解了。
本文深入探讨了“三数之和”问题的多种解决策略,包括暴力求解、使用hashmap以及一种类似快速排序的方法。通过对不同方法的时间复杂度和效率的分析,最终提供了一种在LeetCode上表现优异的解决方案。
7587

被折叠的 条评论
为什么被折叠?



