我们先来看一下这个题目
Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
「Note:」
The solution set must not contain duplicate triplets.
「Example:」
Given array nums = [-1, 0, 1, 2, -1, -4],
A solution set is:
[
[-1, 0, 1],
[-1, -1, 2]
]
题目的在描述,要求出3数之和,并且这三个数字不能在一个数组中重复出现过。
比如例子中的 [-1, -1, 2 ] 出现过后,则不能再出现[-1, 2, -1]这样的顺序不同但数字一样的元素
好的,我们就从上面的例子开始讲解 [-1, 0, 1, 2, -1, -4]这6个数字是一个无须的数字,那么对于我们之间开始操作似乎有点难度, 但要是这些数字都是从小到大排好顺序的话,是不是更容易判断出数字的大小呢? 所以我们先对着6个数字先排序一次
好,我们排序好了以后,我们下一步该是什么呢?
我们想想题目的条件是什么?
- 三个数字之和
- 不能重复
也就是说,我们一次循环最少要获得三个数字,并且判断这3个数字的和是不是我们想要的值
说到这里,应该很多人都有一些思路了,那么我们现在上代码
func threeSum(nums []int) [][]int {
ans := make([][]int, 0)
for i := 0; i < len(nums)-2; i++ {
if nums[i] > 0 {
break
}
if i == 0 || nums[i] != nums[i-1] {
start := i + 1
end := len(nums) - 1
for start < end {
if nums[i]+nums[start]+nums[end] == 0 {
ans = append(ans, []int{nums[i], nums[start], nums[end]})
start += 1
end -= 1
for start < end && nums[start] == nums[start-1] {
start += 1
}
for start < end && end+1 < len(nums) && nums[end] == nums[end+1] {
end -= 1
}
} else if nums[i]+nums[start]+nums[end] < 0 {
start += 1
} else {
//大于0的情况下
end -= 1
}
}
}
}
return ans
}
代码偏长,但是没关系,一点点来理解这些代码的目的是什么
就如我们刚刚所说,我们每一次的判断都必须要获取到3个值,也就是代码中的
start := i + 1
end := len(nums) - 1
这两行代码,那这两行代码的用意是什么? 我们来画个图
这下子,我们每个循环就有了3个数字了,分别是i, start, end这3个指针指向的地方
然后我们再看看, 这两句话上面还有一个 if的作用是什么
if i == 0 || nums[i] != nums[i-1] {
}
就是这个if的作用, 我们看到i==0 就说明是第一个嘛,只要nums[i]<0这个条件就肯定满足,否则在上一个if的时候就会被break掉
那么nums[i] != nums[i-1] 这一句什么时候满足?我们再来看一张图
所以,我们的nums[i] 一定不能跟nums[i-1]一致
那么接下来,我们再内层的循环
for start < end {
if nums[i]+nums[start]+nums[end] == 0 {
ans = append(ans, []int{nums[i], nums[start], nums[end]})
start += 1
end -= 1
for start < end && nums[start] == nums[start-1] {
start += 1
}
for start < end && end+1 < len(nums) && nums[end] == nums[end+1] {
end -= 1
}
} else if nums[i]+nums[start]+nums[end] < 0 {
start += 1
} else {
//大于0的情况下
end -= 1
}
}
循环的开始,我们就是 start<end 这个条件是必须的,否则 就不是最后的3个数字了 接下来到我们一个更核心的判断这个判断有个存在的条件
- 3个数字的和>0
- 3个数字的和<0
- 3个数字的和=0
我们先说case 3 , 3个数字等于0的情况下该如何处理
if nums[i]+nums[start]+nums[end] == 0 {
ans = append(ans, []int{nums[i], nums[start], nums[end]})
start += 1
end -= 1
for start < end && nums[start] == nums[start-1] {
start += 1
}
for start < end && end+1 < len(nums) && nums[end] == nums[end+1] {
end -= 1
}
}
再来画个图 解释一下
可以看到我们红色位置的地方,如果满足条件,那么start向后移动,end向前移动,并且要保持start<end的条件
然后我们来看 start ++ 和end -- 后的两个for是要做什么用的?
for start < end && nums[start] == nums[start-1] {
start += 1
}
for start < end && end+1 < len(nums) && nums[end] == nums[end+1] {
end -= 1
}
我们刚才说过,题目的条件是什么? 「不能重复」, 而这2个for循环就是不重复的关键
前面的 start < end 大家都知道了就不再重复了
后面的nums[start] == nums[start-1] 这个条件是什么意思,再来画个图
start的例子跟end的例子是一样,只不过一个继续往前,一个继续往后,为了就是要保证,我们指向的值,不能跟之前那个值重复,否则就会将重复的值,放进数组中。
到这里,其实很多人都知道核心的步骤是什么了,其实就是这几步
然而刚才的<0跟>0的例子,无非就是start继续往后,跟end继续往前,然后再一次循环判断这3个数字是否一致。
好的,今天的题15就解说到这里,希望自己加油,坚持下去。