给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。
注意: 答案中不可以包含重复的三元组。
示例 1:
输入: nums = [-1,0,1,2,-1,-4]
输出: [[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。
暴力解法(在leetcode中会超时)
这个暴力法是在 两数之和 的基础上加了一重循环,nums[i]相当于 两数之和 中的target
var threeSum = function (nums) {
let resArr = []
let targetArr = []
for (let i = 0; i < nums.length; i++) {
let target = nums[i]
targetArr.push(target)
let arr = []
for (let j = i + 1; j < nums.length; j++) {
if (arr.indexOf(0 - target - nums[j]) === -1) {
arr.push(nums[j])
} else {
let temp = [target, 0 - target - nums[j], nums[j]]
let strtemp = JSON.stringify(temp.sort())
let isSame = false
resArr.forEach(item => {
if (JSON.stringify(item) === strtemp) isSame = true
})
if (!isSame) resArr.push(temp)
}
}
}
return resArr
}
优化之后的解法
先对数组进行排序,遍历数组,nums[i]为target,nums[i+1]及之后的数组中分别设置两个头尾指针,根据头尾相加值与target的大小,决定是移动左指针还是右指针
因为题目中答案中不可以包含重复的三元组的要求,所以需要跳过重复值
var threeSum = function (nums) {
let res = []
nums.sort((a, b) => a - b)
let len = nums.length
if (nums[0] > 0 || nums[len - 1] < 0) return res
for (let i = 0; i < len; ++i) {
// 跳过重复值
if (i > 0 && nums[i] === nums[i - 1]) continue
// 最左侧值为定值,右侧所有值进行两边推进计算
let target = nums[i]
let left = i + 1
let right = len - 1
while (left < right) {
if (nums[left] + nums[right] + target === 0) {
res.push([nums[i], nums[left], nums[right]])
// 跳过重复值
while (left + 1 < len && nums[left++] === nums[left]) { }
while (right - 1 > 0 && nums[right--] === nums[right]) { }
} else if (nums[left] + nums[right] + target > 0) {
right--
} else if (nums[left] + nums[right] + target < 0) {
left++
}
}
}
return res
}