“Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。”
一、题目描述
给你一个包含 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 = []
输出:[]
示例 3:
输入:nums = [0]
输出:[]
提示:
0 <= nums.length <= 3000-105 <= nums[i] <= 105
二、思路分析
这道题是两数之和的进阶版,做过那道题的小伙伴一定知道,使用双指针技巧可以完美解决,这道题当然也是如此。
我们想找和为 target 的三个数字,那么借鉴两数之和的题解,我们可以想到:先找第一个元素,然后再找和为 target-第一个元素 的两个数字(其实这就是找两数之和)。
那么,第一个元素该怎么确定呢,只要确定了第一个元素,剩下的就好办了,直接套用两数之和的题解即可。其实答案很简单,nums 中的每一个元素 nums[i] 都有可能是第一个元素。
想到这里,可以敲代码了,思路如下:
- 先对
nums排序,方便使用双指针。 - 遍历
nums数组,当前元素作为三元组的第一个元素,运用双指针技巧,左指针L为当前元素的下一个元素,右指针R为nums数组的最后一个元素。 - 在
L小于R的前提下,在while循环中判断sum = nums[i] + nums[L] + nums[R]是否等于0,如果小于0则L++,如果大于0则R--,如果等于0则将这三个数压进答案数组,并且L++和R--(为了不让三元组重复,可以循环判断nums[L] == nums[L+1]或者nums[R] == nums[R-1],符合的话就L++或R--,以此提高效率)。 - 需要注意的是,如果
nums数组长度小于3,直接返回空数组即可。
三、AC 代码
/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function(nums) {
let ans = [];
const len = nums.length;
if(nums == null || len < 3) return ans;
nums.sort((a, b) => a - b); // 排序
for (let i = 0; i < len ; i++) {
if(nums[i] > 0) break; // 如果当前数字大于0,则三数之和一定大于0,所以结束循环
if(i > 0 && nums[i] == nums[i-1]) continue; // 去重
let L = i + 1;
let R = len - 1;
while(L < R){
const sum = nums[i] + nums[L] + nums[R];
if(sum == 0){
ans.push([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 (sum < 0) L++;
else if (sum > 0) R--;
}
}
return ans;
};