子集

2018-08-07  本文已影响0人  Houtasu

给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。

说明:解集不能包含重复的子集。

示例:

输入: nums = [1,2,3]
输出:
[
  [3],
  [1],
  [2],
  [1,2,3],
  [1,3],
  [2,3],
  [1,2],
  []
]

解题思路:
最容易想到的就是排列组合的方法,把数组里的元素进行组合排列,选1个元素的有多少种,再选2个元素的有多少种,再选3个元素的...
但这样时间复杂度很高,要遍历很多次,代码写起来也难受(虽然我并没有写)。
那我们思考有没有其他思路,然后,emmm,没想到。。。
不过我们有度娘,找了一下,有个算法叫做深度优先算法,先看下面这张图片

image.png
我们在数学课上学过,一个长度为n的数组的幂集个数等于2的n次方。
以[1,2,3]为例,我们可以这样理解这个定理:
最开始是个空集,什么都没有,然后我们加了一个1进去,现在有两个子集:
[1]和[]
再加个2进去,然后是4个子集:
[1,2] [2] [1] []
可以发现,有一般是原来的子集,还有一般是在原来每个子集中都加了个2。
所以每多一个数,子集总数就翻倍,也就是2的n次方了。
按照这个思路,我们只需遍历数组nums,然后nums中的元素按上面的思路添加到结果集中就好了。
但编程方式有两种,一种是按照上面的流程写,每拿到一个新元素,在老集合的每次子集中添加新元素,还要保留本身老集合中的所有子集。
还有一种是按照先序遍历的方法,上面那张图就是一棵二叉数,获取叶子节点就行了。
第一种代码如下:
def subsets(nums):
    import copy
    res = [[]]
    for i in nums:
        t = copy.deepcopy(res)
        for j in res:
            j.append(i)
        res.extend(t)
    return res

上面就是按照翻倍的思路写的,速度比较慢了,因为用到了深复制。
然而大佬们四行就搞定了,速度还比我的快得多。

 results = [[]]
    for i in nums:
        results = results + [[i] + num for num in results]
    return results

这段代码一眼能看懂什么意思,但要我自己想可能就想不出来了,所以python还有很多地方需要学习和摸索啊。。
然后是使用二叉树的方法:

    def subsets(self, nums):
        self.results = []
        self.search(sorted(nums), [], 0)
        return self.results
    
    def search(self, nums, S, index):
        if index == len(nums):
            self.results.append(S)
            return
        
        self.search(nums, S + [nums[index]], index + 1)
        self.search(nums, S, index + 1)
上一篇 下一篇

猜你喜欢

热点阅读