3Sum
Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
Note:
- Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ≤ b ≤ c)
- The solution set must not contain duplicate triplets.
For example, given array S = {-1 0 1 2 -1 -4}, A solution set is: (-1, 0, 1) (-1, -1, 2)
分析:
这个问题是要从数列里面找到所有和是0的3个数。
对程序输出有两个限制,一是输出的三元组要按升序排列,二是输出的数列要去重,这在编码中会无法避免的导致检查和去重的代码实现。
用map来实现过滤的话,会很容易导致超时,但是在实际应用中,还是觉得用map自动处理比较好理解,而且代码稳定易读。
我写了一个函数,用来清楚表明3 Sum与2 Sum的区别。在这个twoSum里面实现了另外一种Two Sum的解法,略有差别是因为本题不需要返回索引,只要得到正确的数就可以了,所以省略了记录索引的步骤。
class Solution: # @return a list of lists of length 3, [[val1,val2,val3]] def threeSum(self, num): values = [] num.sort() for i, c in enumerate(num[:-2]): if c > 0: break if i == 0 or num[i] > num[i - 1]: values.extend(self.twoSum(num, c, i + 1)) return values def twoSum(self, num, c, start): '''Another way for two sum problem''' c = -c values = [] end = len(num) - 1 while start < end: if num[start] + num[end] == c: values.append([-c, num[start], num[end]]) start += 1 end -= 1 while start < end and num[start] == num[start - 1]: start += 1 while start < end and num[end] == num[end + 1]: end -= 1 elif num[start] + num[end] < c: start += 1 else: end -= 1 return values if __name__ == '__main__': s = Solution() assert s.threeSum([-1, 0, 1, 2, -1, -4]) == [[-1, -1, 2], [-1, 0, 1]] assert s.threeSum([0, 0, 0]) == [[0, 0, 0]] assert s.threeSum([-2, 0, 1, 1, 2]) == [[-2, 0, 2], [-2, 1, 1]] assert s.threeSum([1, -1, -1, 0]) == [[-1, 0, 1]] print 'PASS'
小结:
这个问题与TwoSum结合起来思考的话并不难,但是如果考虑4个数值的衍生情况,是否是O(n^3)的复杂度?
我附带贴上一个更为简洁的代码,但是无法过LeetCode的Online Judge,原因是为了代码的易读可靠超时了。LeetCode不支持set这个数据结构,否则
values = set()
更为简洁,避免了要给dict的value赋上一个值。
def threeSum2(self, num): '''This solution much clear but time out''' values = {} table = dict(zip(num, range(len(num)))) for i, c in enumerate(num[:-2]): for j, b in enumerate(num[i + 1:], i + 1): a = -c - b if a in table and table[a] not in (i, j): values[tuple(sorted((a, b, c)))] = 1 return map(list, values.keys())