「这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战」。
又是算法时间,这道题太折磨我了,改到最后和小伙伴的题解一样了!还是错的,我要崩溃了呀!最后一个一个debugger,才发现问题所在,具体请看下文。
题目描述
给你一个包含 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的任意排序元组,如果是升序,就会大大减少重复三元组的数量;如果用三重for循环暴力拆解,哎,不说了,想想就头疼~
所以,这道题的解题方案为:排序 + 双指针
代码
/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function (nums) {
//判断是否符合三数之和情况
let result = []
if (nums == null || nums.length < 3) return result
//升序排序
nums.sort((a, b) => a - b)
for (let i = 0; i < nums.length; i++) {
//如果nums[i]大于0了,不存在三数之和为0的情况,直接跳出循环
if (nums[i] > 0) break
//这里就是那个坑,主要目的是去重
//注意: 比较的时候,一定是nums[i] 与 nums[i-1] 去比较,不然就会有漏失
if (i > 0 && nums[i] == nums[i - 1]) continue
//定义左指针和右指针
let left = i + 1;
let right = nums.length - 1;
//指针结束条件
while (left < right) {
if (nums[i] + nums[left] + nums[right] == 0) {
result.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) {
right--;
} else if (nums[i] + nums[left] + nums[right] < 0) {
left++;
}
}
}
return result
};