二进制集合操作
二进制集合操作
一个数的二进制表示可以看作是一个集合(
操作 | 集合表示 | 位运算语句 |
---|---|---|
交集 | a & b | |
并集 | a | b | |
补集 | ~a (全集为二进制都是 1) | |
差集 | a & (~b) | |
对称差 | a ^ b |
在进一步介绍集合的子集遍历操作之前,先看位运算的有关应用例子。
模 2 的幂
一个数对
=== "C++"
```cpp
int modPowerOfTwo(int x, int mod) { return x & (mod - 1); }
```
=== "Python"
```python
def modPowerOfTwo(x, mod):
return x & (mod - 1)
```
于是可以知道,
事实上,对于一个正整数
借此可以判断一个数是不是
=== "C++"
```cpp
bool isPowerOfTwo(int n) { return n > 0 && (n & (n - 1)) == 0; }
```
=== "Python"
```python
def isPowerOfTwo(n):
return n > 0 and (n & (n - 1)) == 0
```
子集遍历
遍历一个二进制数表示的集合的全部子集,等价于枚举二进制数对应掩码的所有子掩码。
掩码是一串二进制码,用于和源码进行与运算,得到屏蔽源码的若干输入位后的新操作数。
掩码对于源码可以起到遮罩的作用,掩码中的
给定一个掩码
或者使用更紧凑的 for 语句:
这两段代码都不会处理等于
接下来证明,上面的代码访问了所有
假设有一个当前位掩码
为了使
这两步操作等价于切割掩码
因此,该算法按降序生成该掩码的所有子掩码,每次迭代仅执行两个操作。
特殊情况是
使用
遍历所有掩码的子掩码
在使用掩码动态编程的问题中,有时会希望对于每个掩码,遍历掩码的所有子掩码:
这样做可以遍历大小为
接下来证明,该操作的时间复杂度为
考虑第
- 在掩码
中为 ,因此在子掩码 中为 ,即元素不在大小子集中。 - 在
中为 ,但在 中为 ,即元素只在大子集中,不在小子集中。 - 在
和 中均为 ,即元素同时在大小子集中。
总共有
还有一种证明方法是:
如果掩码
上面的和等于使用二项式定理对
参考资料
本页面主要译自博文 Перебор всех подмасок данной маски 与其英文翻译版 Submask Enumeration。其中俄文版版权协议为 Public Domain + Leave a Link;英文版版权协议为 CC-BY-SA 4.0。
习题
本页面最近更新:2/3/2023, 12:00:00 AM,更新历史
发现错误?想一起完善? 在 GitHub 上编辑此页!
本页面的全部内容在 CC BY-SA 4.0 和 SATA 协议之条款下提供,附加条款亦可能应用