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; - 因为题目要求三元组不能重复,因此需要定义一个辅助数组
help; - 判断条件为三数的和为
0,以及在辅助数组help中不存在; - 因为经历了三层循环,在执行到数组具有大量元素时,超出时间限制;
- 此方法行不通,看方法二。
方法二
- 现将数组排序,方便定义边界值和边界条件;
- 定义左右边界值,
left = i + 1,right = nums.length - 1; - 遍历数组, 以
left < right条件进行while循环 「left > right则三数相加不可能为零」; - 若
(nums[left] + nums[i] + nums[right]) === 0则将[nums[left] + nums[i] + nums[right]]放入结果数组res中,同时给左右边界去重; - 若
(nums[left] + nums[i] + nums[right]) > 0,则证明右边界过大,需要左移,即right--; - 否则,则证明左边界过小,需要右移,即
left++。
AC 代码
方法一
/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function(nums) {
const res = []
const help = []
const len = nums.length
for(let i = 0; i < len; i++) {
for(let j = i+1;j < len;j++) {
for(let k = j+1; k < len; k++) {
if(nums[i] + nums[j] + nums[k] === 0 && !help.includes([nums[i], nums[j], nums[k]].sort().join())) {
res.push([nums[i], nums[j], nums[k]])
help.push([nums[i], nums[j], nums[k]].sort().join())
}
}
}
}
return res
};
结果:
- 315 / 318 个通过测试用例
- 超出时间限制
方法二
/**
* @param {number[]} nums
* @return {number[][]}
*/
const threeSum = function (nums) {
nums.sort((a, b) => a - b)
let res = []
for (let i = 0; i < nums.length; i++) {
let left = i + 1
let right = nums.length - 1
if (nums[i] > 0) break
if (i === 0 || nums[i] !== nums[i - 1]) {
while (left < right) {
if ((nums[left] + nums[i] + nums[right]) === 0) {
res.push([nums[left], nums[i], nums[right]])
while (left < right && nums[left] === nums[left + 1]) left++
while (left < right && nums[right] === nums[right - 1]) right--
left++
right--
} else if ((nums[left] + nums[i] + nums[right]) > 0) {
right--
} else left++
}
}
}
return res
}
结果:
- 执行结果: 通过
- 执行用时:128 ms, 在所有 JavaScript 提交中击败了72.66%的用户
- 内存消耗:50.5 MB, 在所有 JavaScript 提交中击败了64.53%的用户
- 通过测试用例:318 / 318