1.题目
给你一个包含 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 = []
输出:[]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/3sum
2.自己想法及代码
自己的想法比较简单,就遍历每一个数字,用三个for循环,当数字和加起来是0的时候,就把他们放入list中,自己写完并提交后,发现会重复,再解决重复的问题,写好后,不得不说,三个for循环 一定会超时了,那只好看一下别人的思路了,自己的思路代码如下:
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
if(nums.length==0||nums==null)
{
List<List<Integer>> lll = new ArrayList<>();
return lll;
}
HashSet h = new HashSet();//为了解决重复问题,使用hashset
int length = nums.length;
for(int i =0;i<length;i++)
{
for(int j = i+1 ;j<length;j++ )
{
for(int k = j+1;k<length;k++)
{
if(nums[i]+nums[j]+nums[k] == 0)
{
List<Integer> li = new ArrayList<>();
li.add(nums[i]);
li.add(nums[j]);
li.add(nums[k]);
Collections.sort(li);//从小到大的排序 这里是需要排序的
//要不然[-1,0,1]和[1,-1,0]这两个数组是不相等的,
//即使hashset也不能识别出来,这样最后输出就回有问题
h.add(li);
}
}
}
}
List<List<Integer>> lll = new ArrayList<>(h);
return lll;
}
}
这样可以完成简单的三数之和,但是测试用例 很多个数字就不能完成了,那就需要进一步改进了。
3.看别人的想法及代码
想法:
- 将nums排序,这样就变成了从小到大的顺序了
- 从小到大,使用一个双指针,一个在左,一个在右,遍历数组i,那么nums[i]+nums[L]+nums[R]=0
- 去重问题,重新排序的数组 ,两两之间 相等的就略过,不再比较了。
- 在内循环中 始终 L<R, sum=0就加入到list中,并且继续移动L和R,要不然出不了这个while循环。
- 最后返回;
写一下看看吧:
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
//排序
Arrays.sort(nums);//从小到大了
List<List<Integer>> res = new ArrayList();
int len = nums.length;
//开始遍历
for(int i = 0 ; i < len ; i++)
{
if(nums[i] >0 ) break;//说明这个数最小值大于0了
if(i>0&&nums[i] == nums[i-1]) continue;//重复的就不要了
int l = i+1;//这个l不是从0 开始 从0 开始就会出现重复元素了
int r = len -1;
while(l<r)
{
int sum = nums[i]+nums[l]+nums[r];
if(sum == 0)
{
//将这三个元素加入到res中
res.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语句不成立的话 while跳出不了循环 时间超时
else if(sum <0) l++;
else if(sum > 0) r--;
}
}
return res;
}
}
其中需要注意的点在于:
- 虽说是双指针,但左边的指针是从i+1开始的,不能搞错了
- Arrays.asList() 括号中的元素也要从小到大开始,否则输出的时候结果就元素大小顺序有问题。
- if(sum==0)和两个else不能 不写,否则while不能出循环。
4.总结
看到这样的题就想着用循环,循环可以解决,但是一般只能使用两个循环,当使用三个时候,绝大部分都会超时,以后要注意这点,用一个for循环,用一个双指针,避免出现三个循环,三个循环解决实际问题并好;
还有,在三个循环的时候,解决重复问题犯了愁,没想到可以使用排序的方式从小到大,在加一个hashset,这样就可解决重复问题;
还没有熟练掌握Arrays的方法,写的时候可能会少写S,这次用到的方法有Arrays.sort和Arrays.asList();还有Collections.sort是对List排序,Arrays是对数组排序;
自己虽然看了第二个方法的思路,按照他的思路去写,但是没有理解的透彻,所以写着写着就想去看一下答案,看看哪里有问题,比如l和r的定义在for循环内,只写了if没有写else 不能跳出for循环。还有hashset中也用的是add方法添加,对此不熟还百度了。最近做题遇到了双指针较多,以后需要循环的时候也要考虑到。