本文始发于个人公众号:TechFlow
今天介绍的算法题是LeetCode 15题,3 Sum,也成三数求和问题。
Link
难度
Medium
描述
给定一个整数的数组,要求寻找当中所有的a,b,c三个数的组合,使得三个数的和为0.注意,即使数组当中的数有重复,同一个数也只能使用一次。
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.
样例:
Given array nums = [-1, 0, 1, 2, -1, -4],
A solution set is:
[
[-1, 0, 1],
[-1, -1, 2]
]
题解
这道题是之前LeetCode第一题2 Sum的改进版,在之前的题目当中,我们寻找的是和等于某个值的两个数的组合。而这里,我们需要找的是三个数。从表面上来看似乎差别不大,但是实际处理起来要麻烦很多。
暴力求解
我们先理一下思路,从最简单的方法开始入手。这题最简单的方法当然就是暴力法,我们已经明确了要找的是三个数的和,既然数量确定了,就好办了,我们直接枚举所有三个数的组合,然后所有和等于0的组合就是答案。但是这里有一个小问题,当我们找到了答案之后,我们并不能直接返回,因为数组当中重复的元素很有可能会导致答案的重复,我们必须要去掉这些重复的答案,保证答案当中每一个都是唯一的。
那我们先对原数组做处理,去除掉其中重复的元素之后再来寻找答案可不可以呢?
很遗憾,这个想法很好,但是不可行。原因也很简单,因为答案不能重复,但是答案里的数是可以重复的。举个例子,比如数组是[-1, -1, 2, 0, -2],那么[-1, -1, 2]是一个答案,如果一开始就出去掉了重复的-1,那么这个答案显然就无法构成了。唯一的解决方法是用容器来维护答案,保证容器内的答案是唯一的,不过这个会带来额外的时间和空间开销。
所以,总体看来,暴力枚举并不是个好方法,复杂度不低,如果使用C++和Java等语言的话,使用容器也很麻烦。
ret = set()
for i in range(n):
for j in range(i+1, n):
for k in range(j+1, n):
if a[i] + a[j] + a[k] == 0:
ret.add((i, j, k))
return list(ret)
利用2 Sum
还有一个思路是利用之前的2 Sum的解法,在之前的2 Sum问题当中,我们通过巧妙地使用map,来达成了在 O ( n ) O(n) O(n)</