携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第31天,点击查看活动详情
题目描述
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
解题思路——暴力枚举
题目要求我们在数组中找到三个数 a、b、c,使得它们的和为 0,且返回的数据不能重复。那么我们可以通过暴力枚举的方式,一个个去求和,判断三个数的和等于 0 的话,就可以将这三个数看作一个三元组加入到结果集中。
对于一个长度为 n 的数组,我们可以用 三层循环,第一层循环确定 a 的值,范围为 [0, n],第二个循环确定 b 的值,范围为 [a, n],第三个循环确定 c 的值,范围为 [b, n]。
直接通过暴力的方法还是会超时的,不要问为什么,问就是试过。
我们可以对整数数组进行 升序排序,如果前面的和相加大于 0 了,后面就没必要计算了,必然是大于 0 的。同样的,在最后一层循环中,如果 a + b + c === 0 的话,那么对于 c 的下一个数字 d,必然有 a + b + d >= 0,这两种结果都是要 舍弃 的。
题解
/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function(nums) {
const lens = nums.length, res = new Set();
nums.sort((a,b)=>a-b);
for(let i=0; i<lens; ++i) {
if(nums[i] > 0) break;
for(let j=i+1; j<lens; j++) {
if(nums[i] + nums[j] > 0) break;
for(let k=j+1; k<lens; ++k) {
if(nums[i] + nums[j] + nums[k] > 0) break;
if(nums[i] + nums[k] + nums[j] === 0) {
res.add(`${nums[i]},${nums[j]},${nums[k]}`);
break;
}
}
}
}
return Array.from(res).map(i=>i.split(','));
};
解题思路——双指针
双指针也需要将数组先进行一次升序排序。
两层循环,外层循环确定 a 的值, 内层循环找 b 和 c 的值,b 从 a 的下一个位置开始找,c 从数组最后的位置开始找,通过双指针向中间不断逼近移动,遇到 相同的值就跳过,当两个指针相遇时就退出循环。
需要注意的是,即使用双指针也要注意限制条件,最外层循环如果 a > 0 也是将后续的循环直接舍弃了,包括上面提到的相同值跳过,提高遍历效率。
题解
var threeSum = function(nums) {
nums.sort((a,b)=>a-b);
let res = [];
for(let k = 0; k < nums.length - 2; k++){
if(nums[k] > 0) break;
if(k > 0 && nums[k] == nums[k - 1]) continue;
let i = k + 1, j = nums.length - 1;
while(i < j){
let sum = nums[k] + nums[i] + nums[j];
if(sum < 0){
while(i < j && nums[i] == nums[++i]);
} else if (sum > 0) {
while(i < j && nums[j] == nums[--j]);
} else {
res.push([nums[k], nums[i], nums[j]]);
while(i < j && nums[i] == nums[++i]);
while(i < j && nums[j] == nums[--j]);
}
}
}
return res;
};