4Sum

Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.

Note:

  • Elements in a quadruplet (a,b,c,d) must be in non-descending order. (ie, abcd)
  • The solution set must not contain duplicate quadruplets.
    For example, given array S = {1 0 -1 0 -2 2}, and target = 0.

    A solution set is:
    (-1,  0, 0, 1)
    (-2, -1, 1, 2)
    (-2,  0, 0, 2)
分析:
 要从数列中找到4个数其和为给定值的所有组合,与3Sum一样要求输出结果升序和去重。
一个简单直接的想法就是在3Sum解法上再嵌套一层,O(n^3)的时间复杂度,代码是丑陋而且难读的,估计时间上也过不了。
 
重新思考一下解决方案,这个问题是可以化简为O(n^2)的。首先是做一个O(n^2)的计算,将这个数列里面每两个元素的和及其位置放到dict里面记录下来。然后我们的计算就变成
x +y= target
对dict里面的每个值做一次2Sum求值过程(不会超过O(n^2)),问题即可求解。
具体实现过程,有一行代码比较复杂,要解释一下,
map(values.add, [tuple(sorted((num[v1], num[v2], num[v3], num[v4]))) 
                    for v1, v2 in table[b] for v3, v4 in table[a] if len(set((v1, v2, v3, v4))) == 4])
这行代码主要做了4件事情:

  1. 对两个二元组做笛卡尔积,生成4元组列表。如下的代码是做笛卡尔积比较简洁的方式

python -c "print [(x, y) for x in [1,2,3] for y in [4,5]]"

  2. 对4元组去重,保证4元组的索引没有重复。列表去重的简单方式是做set然后看是否其长度和之前一样

len(set((v1, v2, v3, v4))) == 4

  3. 对4元组进行排序,因为sorted生成的是list,还要转成tuple才能作为dict的key存储

  4. 将4元组加入set结构中,对每个元素应用map函数,调用set.add方法

完整代码如下,

class Solution:

    # @return a list of lists of length 4, [[val1,val2,val3,val4]]
    def fourSum(self, num, target):
        table = {}
        for i, a in enumerate(num):
            for j, b in enumerate(num[i + 1:], i + 1):
                table.setdefault(a + b, []).append((i, j))

        values = set()
        for a in table:
            b = target - a
            if b in table:
                map(values.add, [tuple(sorted((num[v1], num[v2], num[v3], num[v4]))) 
                    for v1, v2 in table[b] for v3, v4 in table[a] if len(set((v1, v2, v3, v4))) == 4])
        return map(list, values)

if __name__ == '__main__':
    s = Solution()
    assert s.fourSum([1, 0, -1, 0, -2, 2], 0) == [[-1, 0, 0, 1], [-2, -1, 1, 2], [-2, 0, 0, 2]]
    print 'PASS'

小结:

找到合适的方法这个问题很容易解决。但是对于空间的要求比较高,如果数列很长,无法全部放入内存,应该如何做MapReduce?

原文地址:https://www.cnblogs.com/openqt/p/4039225.html