携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第8天,点击查看活动详情
题目描述
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
输入:nums = [0]
输出:[]
解题思路
此题可以依据两数之和的暴力枚举法,进行三层遍历,取和为0的三元组,并在最后去重,但是不够优雅,直接跳过(ps:太麻烦了! doge)
排序 + 双指针解法:
外层循环:指针 i 遍历数组。 内层循环:用双指针,去寻找满足三数之和为0的元素
-
首先判断数组长度是否小于3,如果为真,直接返回一个空数组
-
对数组进行排序,便于跳过重复元素,如果当前元素和前一个元素相同直接跳过
-
因为需要同时找三个数,所以采取固定一个数,同时用双指针来查找另外两个数的方式。循环数组
nums,假如当前循环到了i索引,则定义两个指针L = i+1,和R = nums.length-1, 计算这三个数(nums[i],nums[L],nums[R])的和 sum,判断和 sum 是否满足为 0,满足则添加进结果集sum = nums[i] + nums[L] + nums[R]a. 如果sum小于0,说明左指针指向的值小,需要向右移动左指针
L++;b. 如果sum大于0,说明右指针指向的值大,则向左移动右指针
R--;c. 如果sum等于0,则正好找到了这3个数,然后在尝试
L++,R--,继续寻找中间是否有三个数之和等于0注意: 在循环的过程中遇见相同的三个数需要去重
/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function(nums) {
let ans = [];
const len = nums.length;
if(nums == null || len < 3) return ans; //数组的长度需要大于3
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; // nums[i] == nums[i-1],则说明该数字重复,会导致结果重复,所以应该跳过( 去重)
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 (nums[L] == nums[L+1]) L++; // 去重
while (nums[R] == nums[R-1]) R--; // 去重
L++;
R--;
}
else if (sum < 0) L++;
else if (sum > 0) R--;
}
}
return ans;
};