简介
今日元宵节,力扣每日一题为Leetcode1178.猜字谜,鄙人愚钝,这条题目想了好久才明白,特此记录。
在用二进制记录哈希映射时,常用1表示选中,0表示未选中。
如 10101表示选中第1、3、5个,其子集应有23 个,其中一个为空集。子集:10101,10100,10001,10000,00101,00100,00001,00000(空集)。
我们设x是表示集合的整数(如上一段中的10101),则其任意一个子集表示的整数y,均有
- y<x
- 二进制表示的y中的1,必须出现在二进制表示的x有1的位置上
所以,我们可以枚举所有小于等于x的数p,并判断p是否满足性质2,若满足则其是x一个子集。这个方法时间复杂度为O(x)。
还有一种方法是令一个数q=x,让q每次减1,再令q = q&x,q即是x的一个子集。下面解释一下这个操作:
- 减1是为了遍历所有比x小的数,减1的实质就是去掉二进制数的最后一个1,并在其后面的位上补上1(如10100-1=10011)。
- &操作是让原来x二进制上是0的位均保持0。
这样保证了q每迭代一次均是比上一个子集小的一个子集。此方法时间复杂度小于O(x)。
代码
mask = 0
for i in range(0,5,2):
mask |= 1 << i
print('mask =',bin(mask))
subsets = [bin(mask)]
subset = mask
while subset:
subset = (subset-1) & mask
subsets.append(bin(subset))
print(subsets)
输出:
mask = 0b10101
['0b10101', '0b10100', '0b10001', '0b10000', '0b101', '0b100', '0b1', '0b0']