题目链接: https://leetcode.com/problems/3sum/
1. 题目介绍(三数之和)
Given an integer array nums, return all the triplets [nums[i], nums[j], nums[k]] such that i != j, i != k, and j != k, and nums[i] + nums[j] + nums[k] == 0.
【Translate】: 给定一个整数数组nums,返回所有的三元组[nums[i], nums[j], nums[k]],使得i != j, i != k, and j != k, and nums[i] + nums[j] + nums[k] == 0。
Notice that the solution set must not contain duplicate triplets.
【Translate】: 注意,解决方案集中不能包含重复的三元组。
【测试用例】:
【约束】:
2. 题解
2.1 穷举再去重 – O(n3)
该题解遍历所有元素,只要满足nums[i] + nums[j] + nums[k] == 0
的条件式,就被存入listAll,遍历完毕之后,我们再对listAll进行去重操作。
private static boolean checkDifferent(List<Integer> list, List<Integer> list1) {
Collections.sort(list);
Collections.sort(list1);
// System.out.println(list.toString().equals(list1.toString()));
return list.toString().equals(list1.toString());
}
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> listAll = new ArrayList<List<Integer>>();
for (int i = 0; i < nums.length; i++)
{
for (int j = i+1; j < nums.length; j++)
{
for (int k = j+1; k < nums.length; k++)
{
if(nums[i] + nums[j] + nums[k] == 0)
{
List<Integer> list = Arrays.asList(nums[i], nums[j], nums[k]);
listAll.add(list);
}
}
}
}
for (int i = 0; i < listAll.size()-1; i++){
for(int j = i+1; j < listAll.size(); j++){
if(checkDifferent(listAll.get(i), listAll.get(j)))
{
listAll.remove(j);
j--;
}
}
}
return listAll;
}
2.2 3sum convert to 2sum – O(n2)
shpolsky在Discuss中提供的解法,目前在Java Most Vote中排名第一。他的思想是对输入数组排序,然后遍历三元组中可能的第一个元素的所有下标。对于每个可能的第一个元素,都对数组的其余部分进行标准的双向2Sum扫描。此外,他们希望跳过相等的元素,以避免在答案中出现重复,而不生成集合或类似的smth。
该题解的核心思想是将3sum问题转变成了2sum问题,然后通过左右指针去解决问题。
public List<List<Integer>> threeSum(int[] num) {
Arrays.sort(num);
List<List<Integer>> res = new LinkedList<>();
for (int i = 0; i < num.length-2; i++) {
if (i == 0 || (i > 0 && num[i] != num[i-1])) { // 初步排除重复元素
int lo = i+1, hi = num.length-1, sum = 0 - num[i];
while (lo < hi) {
if (num[lo] + num[hi] == sum) {
res.add(Arrays.asList(num[i], num[lo], num[hi]));
while (lo < hi && num[lo] == num[lo+1]) lo++;
while (lo < hi && num[hi] == num[hi-1]) hi--;
lo++; hi--;
} else if (num[lo] + num[hi] < sum) lo++;
else hi--;
}
}
}
return res;
}
// 改进之处
// 1. 由于一开始我们就对num数组进行了排序,那么在一开始我们就可以判断num[i]是否大于0,如果大于0直接结束循环,没有答案,可以省下一部分时间。
if(num[i] > 0){
break;
}
// 2. i>0判断冗余,可以直接去掉
3. 可参考
[1] java List一次性添加多个元素
[2] 关于java:如何一次向arraylist添加多个值?
[3] Java如何判断两个集合的元素是否完全相等
[4] Java 之 List<List>
[5] List集合的各种排序
[6] 【Video】3 Sum & 4 Sum (Generalized for k sum) | LeetCode 15 | LeetCode 18 | Medium