15-三数之和
标签:数组 双指针 排序
题目信息
题目地址: 15. 三数之和
题目内容:
javascript
给你一个整数数组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或者数组结尾的数字小于0,则不可能存在三个数相加为0的情况,直接返回遍历数组,获得当前遍历索引
i
,然后定义left
和right
指针,left
指针指向i
的下一位,right
指针指向数组末尾遍历过程中,要先对
i
指向的值去重,然后如果当前i
位置的数字大于0
,就直接返回res
然后计算
i
、left
、right
指向的值的和sum
1、如果
sum大于0
,说明需要减小,将right
指针向左移动一位2、如果
sum小于0
,说明需要增加,将left
指针向右移动一位3、如果
sum等于0
,说明找到了一个满足条件的三元组,将这个三元组加入到res
中,然后需要对left
和right
进行去重,去重结束后,需要将left
和right
分别移动一位最后返回res
代码实现:
javascript
/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function(nums) {
// 将数组从小到大排序
nums.sort((a, b) => a - b)
// 如果数组最小值大于0或者最大值小于0 直接返回
const numsLen = nums.length
if(nums[0] > 0 || nums[numsLen - 1] < 0) return []
const res = [] // 结果
for(let i = 0; i < numsLen; i++) {
// 如果当前的数字是大于0的,那它之后的数字都是比它大的,肯定不可能相加为0,直接返回result
if(nums[i] > 0) return res
// 对i指向的值去重
if(i > 0 && nums[i] === nums[i - 1]) {
continue
}
// 定义left right指针 left 就是i的下一位 right
let left = i + 1, right = numsLen - 1
while(left < right) {
// 计算三个数的和
const sum = nums[i] + nums[left] + nums[right]
if(sum > 0) { // 和大于0 的话 让right 向左移动,减少right指向的值
right--
}else if(sum < 0) { //和小于0的话,让left向右移动,增大left指向的值
left++
}else { // 和等于0记录三个数 并且开始对left和right指向的值去重
res.push([nums[i], nums[left], nums[right]])
while(left < right && nums[left] === nums[left + 1]) {
left++
}
while(left < right && nums[right] === nums[right - 1]) {
right--
}
// 去重后 left和right都要再走一步 这个很关键
left++
right--
}
}
}
return res
};