运算符号
& 与运算
| 或运算
^ 异或运算
<< 左移运算
>> 右移运算
~ 取反运算
利用与1按位与运算判断奇偶
因为偶数变为2进制后最后一位为0,奇数变为2进制后最后一位为1;而1变为2进制后,除了最后一位其余位都为0;所以,偶数与1按位与后为0,奇数与1按位与后为1。
print(6 & 1) # 0
print(4 & 1) # 0
print(8 & 1) # 0
print(3 & 1) # 1
print(1 & 1) # 1
print(5 & 1) # 1计算二进制中1的个数
已知 X&(X-1)可以将最右边的1变为0,那么我们可以一直进行此步骤,直到X为0时,执行次数即为1的个数。
# 验证x&(x-1)的功能
x = 7
print(x & (x - 1)) # 6
x = 4
print(x & (x - 1)) # 0
# 统计二进制串中1的个数
def collect(x):
count = 0
while x != 0:
x = x & (x - 1)
count += 1
return count
print(collect(4)) # 1
print(collect(7)) # 3判断某数是否为2的幂次方
判断X&(X-1)是否为0.因为2的幂次方对应的2进制只有一个1,比如4,8,16。
def pan(x):
if x & (x - 1) == 0:
print("%s是2的幂次方" % x)
else:
print("%s不是2的幂次方" % x)
pan(4) # 4是2的幂次方
pan(5) # 5不是2的幂次方二进制枚举子集
先来介绍一下「子集」的概念。
子集:如果集合 A 的任意一个元素都是集合 S 的元素,则称集合 A 是集合 S 的子集。可以记为 A∈S。
有时候我们会遇到这样的问题:给定一个集合 S,枚举其所有可能的子集。
枚举子集的方法有很多,这里介绍一种简单有效的枚举方法:「二进制枚举子集算法」。
对于一个元素个数为 n 的集合 S 来说,每一个位置上的元素都有选取和未选取两种状态。我们可以用数字 1 来表示选取该元素,用数字 0 来表示不选取该元素。
那么我们就可以用一个长度为 n 的二进制数来表示集合 S 或者表示 S 的子集。其中二进制的每一个二进位都对应了集合中某一个元素的选取状态。对于集合中第 i 个元素来说,二进制对应位置上的 1 代表该元素被选取,0 代表该元素未被选取。
举个例子,比如长度为 5 的集合 S={5,4,3,2,1},我们可以用一个长度为 5 的二进制数来表示该集合。
比如二进制数 11111(2) 就表示选取集合的第 1 位、第 2 位、第 3 位、第 4 位、第 5 位元素,也就是集合 {5,4,3,2,1},即集合 S 本身。如下表所示:
集合 S 中元素位置 | 5 | 4 | 3 | 2 | 1 |
二进位对应值 | 1 | 1 | 1 | 1 | 1 |
对应选取状态 | 选取 | 选取 | 选取 | 选取 | 选取 |
再比如二进制数 10101(2) 就表示选取集合的第 1 位、第 3 位、第 5 位元素,也就是集合 {5,3,1}。如下表所示:
集合 S 中元素位置 | 5 | 4 | 3 | 2 | 1 |
二进位对应值 | 1 | 0 | 1 | 0 | 1 |
对应选取状态 | 选取 | 未选取 | 选取 | 未选取 | 选取 |
再比如二进制数 01001(2) 就表示选取集合的第 1 位、第 4 位元素,也就是集合 {4,1}。如下标所示:
集合 S 中元素位置 | 5 | 4 | 3 | 2 | 1 |
二进位对应值 | 0 | 1 | 0 | 0 | 1 |
对应选取状态 | 未选取 | 选取 | 未选取 | 未选取 | 选取 |
通过上面的例子我们可以得到启发:对于长度为 5 的集合 S 来说,我们只需要从 00000∼11111 枚举一次(对应十进制为 0∼25−1)即可得到长度为 5 的集合 S 的所有子集。
我们将上面的例子拓展到长度为 n 的集合 S。可以总结为:
对于长度为 n 的集合 S 来说,只需要枚举 0∼2n−1(共 2n 种情况),即可得到集合 S 的所有子集。
准备知识:x>>j&1 判断右数第j+1位(从1开始计数)是否为1
def sub(arr):
n = len(arr)
sub_list = []
for i in range(1 << n): # 从0到2^n-1
sub = []
for j in range(n):
if i >> j & 1:
sub.append(arr[j])
sub_list.append(sub[:])
return sub_list
print(sub([1, 2])) # [[], [1], [2], [1, 2]]
print(sub([])) # [[]]
print(sub([1, 2, 3])) # [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]
文章介绍了位运算符,如与(&),或(|),异或(^),左移(<<),右移(>>)以及它们在判断数字奇偶性、计算二进制中1的个数、检测是否为2的幂次方等方面的应用。此外,还阐述了如何使用二进制枚举算法来生成集合的全部子集。
1508

被折叠的 条评论
为什么被折叠?



