15. 三数之和
给你一个整数数组 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] 。
注意,输出的顺序和三元组的顺序并不重要。
示例 2:
输入:nums = [0,1,1]
输出:[]
解释:唯一可能的三元组和不为 0 。
示例 3:
输入:nums = [0,0,0]
输出:[[0,0,0]]
解释:唯一可能的三元组和为 0 。
提示:
3 <= nums.length <= 3000-105 <= nums[i] <= 105
思路:
已知三个数加起来为0,可以简化成确定一个数tmp,找出两个数相加为0-tmp
已知数组中可能存在重复项,可以使用排序算法先进行排序
let arr = nums.sort((a, b) => a - b)
-
sort 方法:
- 用于对数组的元素进行排序,并返回数组
- 若无参数,默认调用数组中每一项的toString方法,按照unicode编码进行排序
- 对于两位数来说,规则是按照每一项第一位比较,相同则第二位,如果是2和13比较,2的unicode是32,1的unicode是31,得出2比13大明显是不对的。
- sort函数可以接收一个函数参数:升序 return a-b
主要思路:
排序后取第一个数,以第一个数arr[i]为基准,找到第一个数之后范围内相加等于0-arr[i]的即可
/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function (nums) {
let arr = nums.sort((a, b) => a - b)
let result = []
let tmp, left, right
//循环遍历数组中的所有数
for (let i = 0; i < arr.length; i++) {
// 如果第一个数大于0,而数组是升序,已知往后的数都大于0,则相加不可能为0
if (arr[i] > 0) break
// 如果前一个数与当前数相同,则可以直接跳过,防止所得答案重复
while (arr[i] == arr[i - 1]) i++
// 找到相加等于tmp的数,三数之和为0
tmp = 0 - arr[i]
// 从i后开始寻找
left = i + 1
// 到长度-1截至
right = arr.length - 1
// 类似快排两边寻找
while (left < right) {
// 满足条件
if (arr[left] + arr[right] == tmp) {
let tmparr = []
tmparr.push(arr[i], arr[left], arr[right])
result.push(tmparr)
// 若区间内存在重复的两个数可以直接跳过,否则答案有重复
while (left < right && arr[left] == arr[left + 1]) left++
while (left < right && arr[right] == arr[right - 1]) right--
left++
right--
// 若比基准大,则说明right的数较大,左移寻找小值
} else if (arr[left] + arr[right] > tmp) {
right--
// 若比基准小,则说明left的数较小,右移寻找小=大值
} else if (arr[left] + arr[right] < tmp) {
left++
}
}
}
console.log(result)
return result
};