Offer 驾到,掘友接招!我正在参与 2022 春招打卡活动,点击查看活动详情。
一、题目描述:
- 三数之和-难度中等
给你一个包含 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 -10^5 <= nums[i] <= 10^5
二、题目和思路分析:
这道题看起来一点也不难,不就是三数之和的情况嘛,还不是轻轻松松,我怎么也没想到自己会从九点多奋战到现在将近三小时才做出来。
最开始我是这么想的:
和为0,则应该有正数,有负数,将数组从小到大进行排序。然后以0为界限,分左右两部分,开始执行下面操作:
-
取左侧最小的两个数字之和的绝对值,右侧大于这个绝对值的数可以删除掉,因为不会有能和它相加为0的两个数。
-
取右侧最大的两个数字之和的相反数,左侧小于这个绝对值的数可以删除掉,因为不会有能和它相加为0的两个数。
-
如果含0,则判断是否存在绝对值相同的正负数,得到答案的一部分,再取不含0的方法得到答案的另一部分。
-
如果不含0,判断左侧任意两数相加的绝对值,是否对应右边某数。再判断右侧任意两数相加的绝对值,是否对应左边某数。
写代码的过程中,我发现考虑不周到,又加了条件:
多个重复数字应单独取出对应的三元组后进行去重处理,即:
非0数字重复次数最多应为2次,0重复次数最多应为3,并且取出000之后去重为0。
就这么在这种条件下,我写的坎坎坷坷,代码加上空行写了一百多行。。。还是一直不对。
眼瞅着马上两个小时了,好像就要成功,但成功又好像总差了一步,于是我想,能不能转换思路呢?
三数相加考虑的情况有点复杂,那么两数相加呢?好像简单了很多啊!!!
设置当前循环的数字为基准数字,然后前面的算法题经常用到双指针,首尾同时遍历,也就是基准数加上双指针进行遍历循环,这不是很容易嘛!
又是一番细节的修修改改不懈努力,终于搞定啦!
三、代码:
代码实现如下:
/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function(nums) {
if(nums == null || length < 3){
return []
}
let arr = [] // 声明空数组
nums.sort((a, b) => a - b) // 数组从小到大进行排序
let length = nums.length
for (let i = 0; i < length ; i++) {
if(nums[i] > 0){ // 如果最小数字大于0,那么和也一定大于0
break
}
if(i > 0 && nums[i] == nums[i-1]){ // 当前数字与上个数字相同,说明已经循环过了,跳出本次循环
continue
}
let left = i+1
let right = length-1
while(left < right){
const sum = nums[i] + nums[left] + nums[right]
if(sum == 0){
arr.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 (sum < 0){
left++
}
else if (sum > 0){
right--
}
}
}
return arr
}
四、总结:
这道题看起来一点也不难,实际上我在这道题却花费了整个晚上。思路错了之后怎么也做不对。
即使是错误的思路,思路转为代码也还是太慢了,其中又因为粗心或者考虑不周,情况兼顾不到,逻辑不完善,修修改改调试最费时间了。
好久没熬夜这么晚了, 加油吧!