题目解读:
这道题是两数之和的延伸,在基础上变得更难了一些,但是可以看到题目中要求是找出三个和为0的元素,也就是定值,而且还要求,nums里面的每一个数字只能使用一遍。
题目思考:
由上面所给出的信息,我们或许可以得到以下想法:
- 如果我们暴力循环,肯定超时
- 既然是和为0,那么是否可以判定,abc最小的一个如果大于0,或者abc最大的一个小于0,都不可能成立,所以可以略过提升性能
- 既然要求数字只能用一遍,那就是去除重复的,我们是否可以考虑一下set呢?但其实是不行的,比如[-1,-2,1,1,1,0],这种时候,就可以这样组合[1,1,-2] [1,1,-2] [1,1,-2],也就是完美利用3个1,所以set不行,我们再想其他方法。
编程逻辑
针对上面的思考,我们做出以下代码的决策:
- 判断abc的大小,肯定需要排序,我们直接用java内置的TimSort就行了
- 拍完顺序发现,可以把问题3也解决了,直接可以用循环跳过重复的数字,避免出现重复组合,也就是,当我们判断while(nums[i]==nums[i+1]) i++,这样就可以跳转到下一个不重复的数字了
- 然后我们还得考虑如何遍历,如果说,a+b+c不是给的定值为0的话,其实快慢指针就可以,但是既然给了0,我们大概都可以想到的,肯定是一个大数带着一个小数,然后一个中等数,凑出来的0,那么我们这个中等数,必然就可以理解为,以这个中等数为轴,然后小数与大数就得从这个轴疏远或者靠近,去完成剩下的遍历,其实两种想法都可行我觉得。但是题目我写的还是靠近。
然后放一下代码:
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
//先排序,然后从左遍历,相同就l++r--,逐步判断就行了
List<List<Integer>> list = 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;
int r = nums.length-1;
while(l<r){
if(nums[l]+nums[r]+nums[i]==0){
list.add(Arrays.asList(nums[l],nums[r],nums[i]));
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]+nums[i]<0){
while (l<r&& nums[l] == nums[l+1]) l++;
l++;
}else{
while (l<r&& nums[r] == nums[r-1]) r--;
r--;
}
}
}
}
return list;
}
}