🚅【leetcode】15. 三数之和
🚀题目
给你一个包含 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 <= nums.length <= 3000
-105 <= nums[i] <= 105
💥leetcode代码模板
/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function(nums) {
};
🚀思路
双指针法:
-
首先对数组进行排序
-
如果排序后第一个元素就大于0,那么不可能存在三数之和为0,返回空数组
-
顺序遍历数组的每一项
nums[i]
,每一个nums[i]
都可以有可能和它之后的2个数字组合,所以定义一个left = nums[i+1] right = nums[nums.length - 1]
。 -
只要
left < right
就执行判断三个数的和的操作,只有3种情况:-
nums[i] + left + right === 0
,将三个数添加到结果数组里。 -
nums[i] + left + right < 0
,和偏小,说明left的值小了(因为数组升序),left++
-
nums[i] + left + right > 0
,和偏大,说明right的值大了(因为数组升序),right--
-
按照上面思路写出以下代码:
var threeSum = function(nums) {
let ans = [] , len = nums.length
nums.sort((a,b) => a - b) // 排序
if(len === 0 || nums[0] > 0) return ans // 数组为空或排序后第一项就为0,返回[]
for(let i = 0 ; i < len ; i++){
let left = i + 1 , right = len - 1
while(left < right){
if(nums[i] + nums[left] + nums[right] === 0) { // 等于0
ans.push([nums[i] , nums[left] , nums[right]])
left++
right--
}else if(nums[i] + nums[left] + nums[right] < 0){ // 小于0
left++
}else{ // 大于0
right--
}
}
}
return ans
};
但是上面的代码还没执行去重操作,所以示例1得到了以下结果
[-1,0,1,2,-1,-4] // 输入
[-4,-1,-1,0,1,2] // 排序后
[[-1,-1,2],[-1,0,1],[-1,0,1]] // 输出
-
上面的三种情况下的操作做完之后,还要各自执行去重的操作,因为题目要求答案中不能包含重复的三元组。
-
首先看
left right
的去重方式,当i
确定下来之后,对于相同的元素,left
和right
都只能取一次。索引下次再遇到相同元素时要越过去。 -
去重时要遵循一个原则,那就是左指针遇到重复取最左,右指针遇到重复取最右。比如:
[-2, -2, -2, -4, -4, -4, -5, -5, 0(i), 0(left), 0, 1, 1, 3, 4, 4(right)]
指针位置标记在数组中,此时right可以取到0,如果是:
[-2, -2, -2, -4, -4, -4, -5, -5, 0(i), 0, 0(left), 1, 1, 3, 4, 4(right)]
即left去重时取的是重复元素的最右边元素,那么right没有机会取到0,这样就遗漏了0,0,0的情况。
💻代码
var threeSum = function(nums) {
let ans = [] , len = nums.length
nums.sort((a,b) => a - b) // 排序
if(len === 0 || nums[0] > 0) return ans // 数组为空或排序后第一项就为0,返回[]
for(let i = 0 ; i < len ; i++){
let left = i + 1 , right = len - 1
// i去重,不能nums[i] === nums[i-1],会漏掉-1,-1,2这种情况
if(i > 0 && nums[i] === nums[i-1]) continue
while(left < right){
if(nums[i] + nums[left] + nums[right] === 0) { // 等于0
ans.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--
}else if(nums[i] + nums[left] + nums[right] < 0){ // 小于0
left++
// 去重
while(left < right && nums[left] === nums[left - 1]) left++
}else{ // 大于0
right--
// 去重
while(left < right && nums[right] === nums[right+1]) right--
}
}
}
return ans
};
🍪总结
这道题用双指针时需要注意去重的方式,遵循某指针去重时不影响其他指针取到值的原则。
✨ 我 是 c o n e r , 请 别 关 注 我 的 专 栏 , 本 系 列 文 章 为 个 人 刷 题 记 录 ( 偷 偷 自 己 卷 🤤 ) : \textcolor{green}{我是coner,请别关注我的专栏,本系列文章为个人刷题记录(偷偷自己卷🤤):} 我是coner,请别关注我的专栏,本系列文章为个人刷题记录(偷偷自己卷🤤):leetcode题解js
✨ 每 天 更 新 l e e t c o d e 题 目 的 j s 题 解 🚀 🚀 🚀 \textcolor{green}{每天更新leetcode题目的js题解🚀🚀🚀} 每天更新leetcode题目的js题解🚀🚀🚀