算法-求集合所有子集
Posted 詩和遠方
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法-求集合所有子集相关的知识,希望对你有一定的参考价值。
问题:求集合所有子集。
下面分别给出两种思路的递归和非递归解法,用python实现。
方法一
a的子集可以分为两部分:
- 不含a[0]的所有子集
- 含a[0]的所有子集(等于将不含a[0]的所有子集都加上a[0])
举例,如下图,[1,2]的子集就是将[1]的子集复制一份再加上2:
总结:a[0:n]所有子集 = a[1:n]的所有子集(不含a[0]) + a[0] + a[1:n]的所有子集(含a[0])
举例:
subset([1,2]) = subset([2]) + 1 + subset([2])
= [],[2] + 1 + ([],[2])
= [],[2] + [1],[1,2]
= [],[1],[2],[1,2]
递归版本:
def subset_sub(ls, index, max_index, result):
"""put all subsets of ls[index:max_index] to result"""
if index == max_index: # if last one, add it to result
result.append(ls[index:])
return
subset_sub(ls, index + 1, max_index, result) # subset of ls[index + 1:]
for x in list(result): # add ls[index] to every element in result
y = list(x) # another list
y.append(ls[index])
result.append(y)
def subset(ls):
if len(ls) == 0:
return [[]]
result = [[]]
subset_sub(ls, 0, len(ls)-1, result)
return result
if __name__ == "__main__":
ls = [1, 2, 3]
result = subset(ls)
for r in result:
print(r)
结果:
[]
[3]
[2]
[3, 2]
[1]
[3, 1]
[2, 1]
[3, 2, 1]
非递归版本:
def subset(ls):
result = [[]] # empty set
if len(ls) == 0:
return result
for i in ls:
for j in range(len(result)): # add to current result with each item in ls
temp_ls = list(result[j])
temp_ls.append(i)
result.append(temp_ls)
return result
if __name__ == "__main__":
ls = [1,2,3]
for r in subset(ls):
print(r)
结果:
[]
[1]
[2]
[1, 2]
[3]
[1, 3]
[2, 3]
[1, 2, 3]
方法二
每个元素的选或不选,分别用0和1来表示,那么长度为3的集合的所有子集,相当于根据000,001,010,011 … 111这样的掩码序列,输出对应的元素,000为空集,111为全集,所以问题转化为了生成所有掩码序列。
递归版本
根据如下规则:
- MaskCode(a[0:n]) = (1 + MaskCode(a[1:n]) + (0 + MaskCode(a[1:n])
递归依次设置每一位的0或1的状态,代码如下:
def subset_mask(index, max_index, working_set,mask_set):
"""put all possible 0/1 mask code of ls[index:max_index] to mask_set"""
if index > max_index:
mask_set.append(list(working_set))
else:
working_set[index] = 0
subset_mask(index + 1, max_index, working_set, mask_set)
working_set[index] = 1
subset_mask(index + 1, max_index, working_set, mask_set)
def subset(ls):
"""generate subsets according to mask codes"""
result = []
mask_set = []
working_set = [0] * len(ls)
subset_mask(0,len(working_set) - 1,working_set,mask_set)
for mask in mask_set:
result.append([j for i,j in zip(mask,ls) if i])
return result
if __name__ == "__main__":
ls = [1, 2 ,3]
result = subset(ls)
for r in result:
print(r)
结果:
[]
[3]
[2]
[2, 3]
[1]
[1, 3]
[1, 2]
[1, 2, 3]
非递归版本
生成掩码的过程也可以借用二进制的形式,比如全集111对应2^3-1=7,000对应0,所以从0到2^n-1转为二进制形式即可生成所有掩码,代码如下:
def subset_mask(length):
"""return all possible 0/1 with length """
mask_set = []
num = 0
while num <= 2 ** length - 1: # max mask code in decimal mode
mask_set.append(str(bin(num))[2:].zfill(length))
num += 1
return mask_set
def subset(ls):
"""generate subsets according to mask codes"""
result = []
mask_set = subset_mask(len(ls))
for mask in mask_set:
result.append([j for i,j in zip(mask,ls) if i == '1'])
return result
if __name__ == "__main__":
ls = [1, 2, 3]
result = subset(ls)
for r in result:
print(r)
结果:
[]
[3]
[2]
[2, 3]
[1]
[1, 3]
[1, 2]
[1, 2, 3]
以上是关于算法-求集合所有子集的主要内容,如果未能解决你的问题,请参考以下文章