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, abc)
  • 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())
原文地址:https://www.cnblogs.com/openqt/p/4038762.html