题目描述
题目链接:力扣https://leetcode-cn.com/problems/3sum/
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
解法要点
这也是力扣热门中等难度的算法题,有一题好像是简单题,跟这个解法类似,是找两个数的组合等于目标值。就是先对数组排序,然后头尾指针指向的数字相加,如果比目标值大,右指针左移,比目标值小,左指针右移。至于为啥这么做,你自己那张纸画画想想吧。
这里稍微难了点,有三个数了,那其实也挺简单,咱们固定一个数,然后对另外俩数做上面的操作,移动的两个数碰到了,固定的那个数就指向下一个。
有个比较容易出错的坑,就是要去除重复的组合,这样,我们在固定数字循环,和头尾指针移动的时候碰到相同的数字都要直接跳过。跳过的时机有讲究,第一次碰到时不能跳,必须用过后,再碰到,才能跳过,否则会漏掉一些组合。
比如 -1 -1 2 3,如果碰到 第一个 -1时直接跳到第二个数字,那么你就一个和为 0 的组合都找不着。左右指针移动时也要注意相同的点,相同的数字不能碰见就跳过,但是用过之后一定要跳过。
代码
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> ansList = new ArrayList<>();
if(nums == null){
return ansList;
}
int len = nums.length;
if(len < 3){
return ansList;
}
// 老规矩,先排序
Arrays.sort(nums);
// 注意,i的循环范围,最大到 i-3 的下标,后面还得留俩数
for(int i = 0; i < len-2; i ++){
int num = nums[i];
if(num > 0){ //固定的值是三个数中最小的,它都大于0了,后面就不用再试了
return ansList;
}
// 这里必须判断 num == nums[i-1],而不能是 num == nums[i+1],否则会导致相同数字中前面的那些没用到
if(i > 0 && num == nums[i-1]){
continue;
}
int l = i+1;
int r = len-1;
while(l < r){
int sum = num + nums[l] + nums[r];
if(sum > 0){
r--;
} else if (sum < 0){
l++;
} else {
// 如果满足条件了,还等往下试,因为如果 l 大一点,r 再小一点,也是可能的
List<Integer> ans = Arrays.asList(num, nums[l], nums[r]);
ansList.add(ans);
// 为了避免重复,碰到相同的数字,我们对 l 取最右,对 r 取最左
// 必须放在这里跳过相同数字,因为这里才能确保它们都被用过
while(l<r && nums[l] == nums[l+1]){
l++;
}
while(l<r && nums[r] == nums[r-1]){
r--;
}
r--;
l++;
}
}
}
return ansList;
}
}
现在,关于三数之和这道题,你已经知道得和我一样多了~
本专栏定期更新力扣算法讲解,希望以最容易记忆的方式帮你搞定面试算法题。