Python刷题:用二进制方式求集合S的所有子集(位运算)

题目描述

有一个集合S,要求打印出其所有子集,子集元素用逗号隔开,其中集合S本身和空集NULL都认为是集合S的子集。例如,有一个集合S,它的内容为“S={"A", "B", "C"}”,那么该集合S的所有子集为“A,B,C”、“A,B”、“AC”、“BC”、“A”、“B”、“C”、“NULL”。

解题思路

先要思考如何将集合求子集这个操作与二进制联系起来,首先可以确定,集合S、空集以及单个元素的子集很容易确定,不用与二进制关联也可以轻松得到,剩下的子集的求解思路就是某个元素不在子集中时,剩下的所有元素为一个子集,然后依次是某两个元素不在子集中时剩下的元素为一个子集,以此类推,就可以得到所有子集。联想二进制的特点,一个比特位上要么是0,要么就是1,那么可以使用比特位代表每个元素,它的值为1时表示此元素在子集中,值为0时表示此元素不在子集中,然后根据“题目”中的例子,将集合S的所有子集用二进制表示出来,然后写出对应的十进制就可以看到对应的规律了。

子集 二进制 十进制
A,B,C 0b111 7
A,B 0b110 6
A,C 0b101 5
A 0b100 4
B,C 0b011 3
B 0b010 2
C 0b001 1
NULL 0b000 0

解题代码

def print_sub(val, s):
    # 获取对应位数的二进制位字符串
    bin_str = bin(val).replace('0b', '').rjust(len(s), '0')

    idx = 0
    is_null = True
    while idx < len(s):
        # 如果该比特位为1,则打印对应的元素
        if bin_str[idx] == '1':
            if not is_null:
                print(',', end='')

            is_null = False
            print(s[idx], end='')

        idx += 1

    if is_null:
        print('NULL', end='')

    print(';')

def func(s):
    # 使用二进制的方式得到所有元素都存在时的二进制表示方式对应的十进制数
    # 当然,也可以使用其他方式得到这个值
    val = 0
    for i in range(len(s)):
        val |= (1 << i)

    # 遍历并打印每一个子集
    while val >= 0:
        print_sub(val, s)
        val -= 1

if __name__ == '__main__':
    collection = ['A', 'B', 'C', 'D']
    func(collection)

输出:

A,B,C,D;
A,B,C;
A,B,D;
A,B;
A,C,D;
A,C;
A,D;
A;
B,C,D;
B,C;
B,D;
B;
C,D;
C;
D;
NULL;

总结

求集合的子集,在Python中itertools.combinations也可以做到,或者自己编写另外的算法,但是就此题而言,相当于是提供了另一种解题思路或者说是二进制的一种操作方法,可以参考下。

题目及解题算法来自:书籍《Python程序员面试宝典》。

(0)

相关推荐