题目
有一个集合S,要求打印出其所有子集,子集元素用,
隔开。比如集合S ={“A”,“B”},其子集分别为,“A,B” ,“A”, “B” ,NULL 四个。其中S本身和空集都可以认为是S的子集。
算法描述
以S ={“A”,“B”,“C”}为例,集合中包含三个元素,那么让S对应3个位长的二进制数,在子集中取1,不在子集中取0,即:
111(7)->A B C
110(6)->A B
101(5)->A C
100(4)->A
011(3)->B C
010(2)->B
001(1)->C
000(0)->NULL
代码实现
def fixBinaryString(val, setlen):
'''
必须保持val的二进制长度与集合长度一致,例如如果集合有3个元素,val=2,那么它的二进制形式是0b11
函数在高位补足一个0,于是0b11转换为0b011,这样在打印集合元素时才能根据二进制位对应得上每一个元素
'''
binary = bin(val).replace('0b', '')
while len(binary) < setlen:
binary = "0" + binary
return binary
def printSetByBinary(val, collection):
'''
根据整数二进制形式中比特位上的值是0还是1选择是否把对应元素打印到子集中
'''
# 先把整形对应的二进制位数根据集合元素个数补全
binary = fixBinaryString(val, len(collection))
idx = 0
isNull = True
while idx < len(binary):
# 如果对应比特位是1,那么就打印对应的集合元素
if binary[idx] == '1':
if isNull is False:
print(",", end='')
print(collection[idx], end='')
isNull = False
idx += 1
if isNull is True:
print("NULL")
print(";")
def handleAllSubSet(set):
count = len(set)
val = 0
# 根据集合中元素的个数构造相应位长的二进制数,并把所有对应的比特位都设置为1
for i in range(count):
val |= (1 << i)
while val >= 0:
printSetByBinary(val, set)
val -= 1
collection = ["A","B","C"]
handleAllSubSet(collection)
运行结果:
A,B,C;
A,B;
A,C;
A;
B,C;
B;
C;
NULL
;
算法分析
对于一个n位长的二进制数,所有可能取值的情况公有2^n种,因此算法的复杂度就是O(2 ^n)。这种指数级的时间复杂度效率是很低的,但就这种问题而言,我们更注重的应该是解题思路,算法效率并不是重点。