15. 3Sum
Posted limaodeng
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了15. 3Sum相关的知识,希望对你有一定的参考价值。
1.题目描述
英文版:
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]]
中文版:
给一个长度为n的数组nums。在数组nums里面有三个数a,b,c。并且a + b + c = 0。
在数组中找出所有唯一的三元组,其总和为零。
注意:
在结果集里面必须不能包含重复的三元组。
例如:
数组 nums = [-1, 0, 1, 2, -1, -4],
它的结果集:
[
[-1, 0, 1],
[-1, -1, 2]]
2.解法
2.1 解法1
思路:
看到这一题,最先的想法也是暴力破解法。三重循环分别遍历所有数的三元组之和,遍历之前先进行排序,后面用来比较是否为重复三元组。但是这种写法很明显,时间复杂度实在是太高了,在LeetCode上运行没有通过。
public static List<List<Integer>> threeSum1(int[] nums) {
Arrays.sort(nums); //先进行排序,后面方便查重
List<List<Integer>> lists = new ArrayList<>();
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 = new ArrayList<>();
list.add(nums[i]);
list.add(nums[j]);
list.add(nums[k]);
//判断lists里面是否包含有元素一模一样的list,如果有则不添加,如果没有则添加
AtomicBoolean b = new AtomicBoolean(false);
lists.forEach(li -> {
if(li.get(0)==list.get(0)&&
li.get(1)==list.get(1)&&
li.get(2)==list.get(2)){
b.set(true);
}
});
if(!b.get()){
lists.add(list);
}
}
}
}
}
return lists;
}
在LeetCode上运行的结果:
2.2 解法2
思路:
这种解法较好地优化了时间复杂度。首先在遍历之前也选对数组进行排序,方便后面操作。排好迅之和,从左边到右边,先找到i位置对应的数,再找出start位置和end位置的数,使他们相加起来等于i位置的数的相反数,这就是一组数。其中start的位置从i+1开始往后移,end的位置从nums.length - 1开始往前移。
注意的点:
1、只循环到倒数第三个数即可
2、如果nums[i]大于零,说明后面没有数跟它相加起来等于零了
3、空数组则直接返回
4、如果第i个的前一个与它相等,则跳过,避免重复三元组
5、第start+1的数与第start相等则跳过,继续往后找,避免重复三元组
6、第end - 1的数与第end相等则跳过,继续往前找,避免重复三元组
7、如果nums[start] + nums[end] < target ,则说明start所处的位置还太小,start继续往后找
8、如果nums[start] + nums[end] > target,则说明end所处的位置还太大, 则end继续往前找
代码实现:
public static List<List<Integer>> threeSum2(int[] nums) {
List<List<Integer>> lists = new ArrayList<>();
Arrays.sort(nums); //先对数组进行排序
for(int i = 0;i < nums.length - 2;i++){ //只循环到倒数第三个数即可
if(nums[i] > 0) break; //如果nums[i]大于零,说明后面没有数跟它相加起来等于零了
if(nums.length == 0) break; //空数组则直接返回
if(i > 0 && nums[i] == nums[i-1]) continue; //如果第i个的前一个与它相等,则跳过,避免重复数据
int target = 0 - nums[i]; //将第i个数变成正数
int start = i + 1; //start从第i+1开始往后移
int end = nums.length - 1; //end从第nums.length - 1开始往前移
while (start < end){
if(nums[start] + nums[end] == target){ //num[i] + nums[start] + nums[end] = 0
List<Integer> list = new ArrayList<>();
list.add(nums[i]);
list.add(nums[start]);
list.add(nums[end]);
lists.add(list);
while (start < end && nums[start] == nums[start + 1]) //第start+1的数与第start相等则跳过,继续往后找
start++;
while (start < end && nums[end] == nums[end - 1]) //第end - 1的数与第end相等则跳过,继续往前找
end--;
start++;
end--;
}else if(nums[start] + nums[end] < target){ //nums[start] + nums[end] < target 则start继续往后找
start++;
}else { //nums[start] + nums[end] > target 则end继续往前找
end--;
}
}
}
return lists;
}
在LeetCode上运行的结果:
3.测试
在本地,我只是简单写了一个main函数来对它进行测试。但是这些代码都是在LeetCode上运行通过了的。
public static void main(String[] args) {
int[] nums = {-1, 0, 1, 2, -1, -4};
List<List<Integer>> lists = threeSum2(nums);
lists.forEach(s -> {
s.forEach(k -> System.out.print(k + " "));
System.out.println();
});
}
欢迎关注个人公众号,可直接扫描以下二维码或微信搜索“阿毛聊技术”。
以上是关于15. 3Sum的主要内容,如果未能解决你的问题,请参考以下文章