题目描述 - 三数之和
给定一个整数数组 nums
,判断是否存在三元组 [nums[i], nums[j], nums[k]]
满足 i != j
、i != k
且 j != k
,同时还满足 nums[i] + nums[j] + nums[k] == 0
。返回所有和为 0
且不重复的三元组。
注意: 答案中不可以包含重复的三元组。
思路分析
最直白的方法是通过三重循环,遍历数组中所有元素, 找到三数之和为0的元素, 但是三重遍历时间复杂度是:O(n3)。我们可以双指针来降低复杂度。
先将数组进行升序排列,保证按顺序查找 a
、b
、c
时,所找到的三个元素是不重复的。同时也方便下一步使用双指针减少一重遍历。
第一重循环遍历 a
,对于每个 a
元素,从 a
元素的下一个位置开始,使用左右双指针 left
,right
。left
指向 a
元素的下一个位置,right
指向末尾位置。进行下边的判断。
- 如果
nums[a] + nums[left] + nums[right] = 0
,判断left
右移,和right
元素是否重复, 若不重复,则得到一个解,将其加入答案数组中,并继续将left
右移,right
左移; - 如果
nums[a] + nums[left] + nums[right] > 0
,说明nums[right]
值太大,将right
向左移; - 如果
nums[a] + nums[left] + nums[right] < 0
,说明nums[left]
值太小,将left
右移。
代码:
/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function(nums) {
nums = nums.sort((a,b)=>a-b)
let ans = []
for(let i=0; i<nums.length; i++){
if(i>0 && nums[i]== nums[i-1]) continue
let current = nums[i];
let left = i+1, right = nums.length - 1;
while(left < right){
if(current + nums[left] + nums[right] == 0){
while(left < right && nums[left] == nums[left + 1]){
left++
}
while(left < right && nums[right] == nums[right - 1]){
right--
}
ans.push([current, nums[left], nums[right]])
right--
left++
}else if(current + nums[left] + nums[right] > 0){
right--
}else {
left++
}
}
}
return ans
};