二进制位运算遍历所有子集

二进制位运算遍历所有子集

简介

今日元宵节,力扣每日一题为Leetcode1178.猜字谜,鄙人愚钝,这条题目想了好久才明白,特此记录。

在用二进制记录哈希映射时,常用1表示选中,0表示未选中。
10101表示选中第1、3、5个,其子集应有23 个,其中一个为空集。子集:1010110100100011000000101001000000100000(空集)。

我们设x是表示集合的整数(如上一段中的10101),则其任意一个子集表示的整数y,均有

  1. y<x
  2. 二进制表示的y中的1,必须出现在二进制表示的x1的位置上

所以,我们可以枚举所有小于等于x的数p,并判断p是否满足性质2,若满足则其是x一个子集。这个方法时间复杂度为O(x)。

还有一种方法是令一个数q=x,让q每次减1,再令q = q&xq即是x的一个子集。下面解释一下这个操作:

  1. 减1是为了遍历所有比x小的数,减1的实质就是去掉二进制数的最后一个1,并在其后面的位上补上1(如10100-1=10011)。
  2. &操作是让原来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']
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值