leadcode的Hot100系列--78. 子集

看一个数组的子集有多少,其实就是排列组合,
好比:[0,1] 对应的子集有:[] [0] [1] [1,1] 这四种。
通常对应有两种方法:位运算回溯
这里先使用位运算来作。python

位运算

一个长度为n的数组,对其作排列组合,能够理解为:这n个数字中,有哪些是存在的,哪些是不存在的。
例如,数组为[1,2,3],能够组合为:[1,2],则说明1和2是存在的,3是不存在的,
咱们能够这么规定一下: 用1标记为存在,0标记为不存在
那么[1,2]这个组合就能够用 110来标记,[1,3]的组合就能够用101来标记,[]的组合就能够用000来标记。
(注:这里为方便理解,将数组直观的位置与标记一一对应,而不考虑数组下标,
实际代码中,是用下标来作对应的)
这样的话:数组

数组的排列组合问题,就转换为每一个数字的存在或者不存在的问题。app

这里有三个数字,每一个数字都会有存在和不存在的两种状况,总共就会有8种排列,分别是:
000,001, 010, 011, 100, 101, 110, 111
对应的数组分别是:
[],[3],[2], [2,3], [1], [1,3], [1,2], [1,2,3]code

重点来了:若是把上面的01标记当作二进制数字的,那对应的十进制数字就是0,1,2,3,4,5,6,7。
这里先统称这些数字为flag(用来标记对应位置的数字是否存在)。
因此,当我已经知道总共的组合有n种的时候,那么就会有 0 到 (n-1) 个 flag 来标记对应位置的数字是否存在。
那么代码中是怎么对应的呢?此次用数组[6,7,8]来举例。
数字6,7,8对应的下标分别是 0,1,2,对应的位置就是 (1 << 下标),
那么:6对应的是flag中的第1位(1<<0),7对应的是flag中的2位(1<<1),8对应的是flag中的第3位(1<<2)。
因此,实际代码中 当flag = 1 (二进制位001)的时候,对应的组合是 [6],flag = 3(二进制位011)的时候,对应的组合是[6,7]。io

ps:由于题目要求输出的形式是:[[],[3],[2],[2,3],[1],[1,3],[1,2],[1,2,3]]
这个的话,感受用c不太好实现,因此就偷偷用了python来实现了,但原理仍是同样的!class

class Solution(object):
    def subsets(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        subList = []
        length = len(nums)
        totalCount = pow(2, length)     # 获得子集的总个数
        for flag in range(totalCount):   # 遍历各个flag标记
            sub = []
            for xiabiao in range(length):  # 遍历数组下标,查看对应位置的数字是否存在
                if flag & (1<<xiabiao):
                    sub.append(nums[xiabiao])  # 若是对应的数字存在,就把该数字放入新数组中
            subList.append(sub)
        return subLis
相关文章
相关标签/搜索