题目:三数之和
给定一个包含 n 个整数的数组 nums
,判断 nums
中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组
例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/3sum
解题思路:双指针
首先题目要求结果不包含重复三元组,而在给出的nums
中又可能出现重复的元素,因此可以先对nums
进行一次排序,这样做的意义一是方便使用双指针,二是遍历中也方便跳过重复项
那么应该怎样找出三个相加为0的三元组呢?具体步骤如下:
- 先找出一个基点,假设这个基点索引为
i
,nums
长度为n
,那么剩下2个与基点相加为0的元素就是在[i+1,i+2,.....,n-2,n-1]
中寻找 - 确定寻找范围后,就可以依靠双指针法,如下图:
假设
j=i+1
,k=n-1
,然后判断nums[i]+nums[j]+nums[k]
的值是否为0,从上图可以看出-2-1+4>0
,所以k
值要往左移动,如下图:k
往左移动后nums[i]+nums[j]+nums[k]
相加刚好为0,那么就可以把这个三元组放进结果数组中 - 在找到基点的第一组三元数组后并不意味着开始前往下一个基点,相反当前基点
nums[i]
可能存在2个及2个以上三元数组,所以需要以当前基点寻找,如下图: 在找出第一组三元数组后,j
加一,k
减一,这个时候nums[i]+nums[j]+nums[k]
同样为0,如下图 - 最后只剩下一些边界条件的处理,比如:
1.当基点大于0的时候,就代表不符合题目条件,直接返回结果
2.当基点与前一个基点相同时,跳过本次循环
3.如上面说到的基于当前基点继续寻找三元数组时,j
和k
都要各自往左右移动,那么在左移或右移后有可能碰到相同项,那么就需要继续移动
代码实现
let threeSum = (nums) => {
if (nums.length < 3) return []
let sum,
result = [];
nums = nums.sort((a, b) => {
return a - b
});
for (let i = 0; i < nums.length - 2; i++) {
let a = nums[i]
if (a > 0) return result;
if (i > 0 && a === nums[i - 1]) continue;
let j = i + 1, k = nums.length - 1;
while (j < k) {
let b = nums[j],
c = nums[k],
sum = a + b + c;
if (sum === 0) {
result.push([a, b, c]);
j++;
k--;
while (nums[j] === b) {
j++
}
while (nums[k] === c) {
k--
}
} else if (sum > 0) {
k--
} else {
j++
}
}
}
return result
};