(1)判断数字x的每一位没有重复数字(位运算用作集合)
bool check(int x){
int status = 0; //标志状态变量,每一位分别表示数字9876543210是否出现过
while (x){
int bit = 1 << (x % 10);
if (status & bit != 0) return false; //之前已经出现过
status |= bit; //添加某一位应该是 |= 而不是 &=
x /= 10;
}
return true;
}
(2)得状态码
int get_status(long long m){ //仅仅针对没有重复数字的!!!
if (m == 0) return 1; //如果m是0的话,得到的状态应该是01,所以应该单独讨论!!!
int status = 0;
while (m){
int bit = 1 << (m % 10);
status = status | bit;
m /= 10;
}
return status;
}
(2)判断两个数字的每一位是否出现了重复(位运算用作集合)
比如:36和64都出现了6
36 状态为 0001001000,64 状态为 0001010000
0001001000 & 0001010000 == 1这时就发生了重复
根据(1)得到status 然后 & ,如果是1则发生了重复,否则没重复。
(3)判断当前状态是否出现了0-9全部的数字 (位运算用作集合)
if (status == (1 << 10) - 1) return true;
return false;
(4)A 和 B出现是在n个位置上的组合,A和B个数都是0到n
for (int i = 0; i < (1 << n); ++i){
...
}
(5)异或(不同为1,相同为0):不同为B,相同为A。
假设当前层i>0状态变量为x,上一层为 异或+把最高位置为0
x = x ^ (x >> 1);
x &= (1 << (i-1)) - 1; //某位置置为0,&该位为0,其他都为1 !!!
(6)判断一个整数的二进制中,有多少个1。
(num-1)&num 就会把num最右边的‘1’给去掉。 因为-1之后100会变成001,&一下最右边的’1’就没了 !!!
int nbit(int num){
int ans = 0;
while (num){
ans++;
num = (num - 1) & num;
}
return ans;
}
(7) 判断int变量a后30位是否存在相邻两个都是1的情况。
int j = 3; //011
for (int i = 0; i < 28; ++i){
if (a & j == j) return true; //别少了==j,因为需要两位都满足等于1
j <<= 1;
}
return false;
(8)把最右边那个1左边的数字改变。
^1 实现翻转, ^0不变
…x1000 需要 ^ …10000,怎么凑?
…x1000 -> …x1111 再+1 就是10000,所以
//a ^ (a-1)就是把第一个1右边的都搞成1 !!!
tmp = (a ^ (a - 1)) + 1;
a ^= tmp;
(9)元素对应二进制中最左边‘1’所对应的位置。
int block = 1;
while ((1 << block) <= each) {
block++;
}
return block - 1;
(10)小总结:
1:a ^ (a-1)就是把第一个1右边的都搞成1,其他不变。
2:(a-1)&a 就是把a最右边的‘1’给去掉
3:
#define lowbit(x) (x & (-x))是取最右边的1,其他均为0的数。
x -= (x & (-x)) 是把最右边的1去掉,所以等价于x = (x - 1)& x; !!!
3.求进制的值
ans = 0;
for (int i = 0; i < str.size(); ++i){
ans = ans * jinzhi + str[i];
}
4.汉明权重
方法二:
__builtin_popcount(num);
方法二:
int nbit(int num){
int ans = 0;
while (num){
ans++;
num = (num - 1) & num;
}
return ans;
}
// 求 x 的汉明权重
int popcount(int x) {
int cnt = 0;
while (x) {
cnt += x & 1;
x >>= 1;
}
return cnt;
}
// 求 x 的汉明权重
int popcount(int x) {
int cnt = 0;
while (x) {
cnt++;
x -= x & -x;
}
return cnt;
}
5.子集遍历:
// 遍历 u 的非空子集
for (int s = u; s; s = (s - 1) & u) {
// s 是 u 的一个非空子集
}
6.常用的二进制函数
求int变量中1的个数:
cout << __builtin_popcount(num);
求long long变量中1的个数:
cout << __builtin_popcountll(num);
求int变量中位的个数:
cout << 32 - __builtin_clz(num);
求long long变量中位的个数:
cout << 64 - __builtin_clzll(num);