位运算
位运算的基本操作
typedef struct Bitset { int setsize; // 16 32 ... int 是32位的 int arraysize; // 相当于有几行 unsigned short *v; // 之后会分配一片连续的空间 }Bitset; //还非要大写才行 .. // SetInit(size) 集合大小 Bitset SetInit(int size) { Bitset s; s.setsize = size; s.arraysize = (size + 15) >> 4; // 右移4位 除以16 //我之前好像智障了 sizeof后面的是不需要看的 肯定是要带上的 所以这行就是相当于 创建一个sizes长度的v 类型是unsigned short型 s.v = (unsigned short*) malloc( size * sizeof(unsigned short)); for (int i = 0; i < size; i++) { s.v[i] = 0; // 初始化 } return s; } // SetAssign(A, B) 将集合B 复制 到集合A void SetAssign(Bitset A, Bitset B) { if(A.setsize!=B.setsize) exit(-1); for(int i = 0; i < A.arraysize; i++) A.v[i] = B.v[i]; //定义是按照n定,赋值是按照层d赋值 } // SetMember(x, A) 判断是否是相同类型 /* 首先明确一点 就是集合A的元素{1,3,5} 它代表的是 第1、3、5位的数字为1 也就是 101010 而元素x : 若 x=2 则表示判断 第x位是否为1。 现在假设传入的x=28 说明我要找的是第28位的数字 x >> 4 = 1 说明我应该去v[1]找 x & 15 = 12 相当于mod 16 = 12 , 再将 1 右移 12位 ,就是相当于 把v中第13个数 和 1 相与 */ int findIndex(int x) { return x >> 4; // 找下标 } int bitIndex(int x) { return 1 << (x & 15); } int SetMember(int x, Bitset A) { if (x<0 || x > A.setsize) exit(-1); return A.v[findIndex(x)] & bitIndex(x); } // SetEqual(A, B) 两集合是否相等 int SetEqual(Bitset A, Bitset B) { if(A.setsize!=B.setsize) exit(-1); for(int i = 0; i < A.arraysize; i++) { if(A.v[i]!=B.v[i]) return 0; } return 1; } // SetUnion(A, B) U 并集合 Bitset SetUnion(Bitset A, Bitset B) { Bitset C = SetInit(A.setsize); if(A.setsize!=B.setsize) exit(-1); for(int i = 0; i < A.arraysize; i++) { C.v[i] = A.v[i] | B.v[i]; } return C; } // SetInterSection(A, B) 交集 -> C.v[i] = A.v[i] | B.v[i]; // SetDifference(A, B) 差集 属于A而不属于B的 Bitset setDifference(Bitset A, Bitset B) { Bitset C = SetInit(A.setsize); if(A.setsize!=B.setsize) exit(-1); for(int i = 0; i < A.arraysize; i++) { C.v[i] = A.v[i] ^ (A.v[i] & B.v[i]); // 这步骤就是把,A B都有的元素取出,再异或一下,不同取1,就可以拿出差集了。 } return C; } // SetInsert(x, S) 在x位插入元素 Bitset SetInsert(int x, Bitset S) { if(x<0 || x > S.setsize) exit(-1); S.v[findIndex(x)] |= bitIndex(x);// 妈耶 我怎么会把它想那么复杂呢 return S; } // SetDelete(x,S) 在x位删除元素 Bitset SetDelete(int x, Bitset S) { if(x<0 || x > S.setsize) exit(-1); S.v[findIndex(x)] &= ~bitIndex(x); // x位为0,其余都是1,&上之后,可以成功删除 return S; }
一般操作
// 求n的第k位数字: n >> k & 1 //返回n的最后一位1: lowbit(n) = n & -n
逆转二进制数
int rever(int num) { int m_1 = 0x55555555; // 0101 8对 int m_2 = 0x33333333; // 0011 8对 int m_4 = 0x0f0f0f0f; // 00001111 4对 int m_8 = 0x00ff00ff; int m_16 = 0x0000ffff; int b = ((num & m_16) << 16) + ((num >> 16) & m_16); // 右挪左,左侧右移16位 int c = ((b & m_8) << 8) + ((b >> 8) & m_8); int d = ((c & m_4) << 4) + ((c >> 4) & m_4); int e = ((d & m_2) << 2) + ((d >> 2) & m_2); int f = ((e & m_1) << 1) + ((e >> 1) & m_1); return f; } int main() { int a = 67; int b = rever(a); int c = rever(b); printf("%d %d", a, c); return 0; }
leetcode.762 二进制表示中质数个计算置位
题目:给定两个整数 L 和 R ,找到闭区间 [L, R] 范围内,计算置位位数为质数的整数个数。(注意,计算置位代表二进制表示中1的个数。例如 21 的二进制表示 10101 有 3 个计算置位。还有,1 不是质数。)
int countPrimeSetBits(int L, int R) { int res = 0; unordered_set<int> primes({2, 3, 5, 7, 11, 13, 17, 19}); for (int i = L; i <= R; i ++ ) { int s = 0; for (int j = i; j; j >>= 1) s += j & 1; if (primes.count(s)) res ++; } return res; }
leetcode.231 2的整次幂
题目:给定一个整数,编写一个函数来判断它是否是 2 的幂次方。
bool isPowerOfTwo(int n) { return n > 0 && ( n & -n ) == n; }
leetcode.136 只出现一次的数字
题目:给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
// 输入 [1,2,3,1,2,3,4] int singleNumber(vector<int>& nums) { int res = 0; for(auto x : nums) res ^= x; return res; }
leetcode.136 只出现一次的数字II
题目:除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。
题解:统计每一列1的个数,是3的倍数,表明 贡献了该位的数字是3的整数; 反之,如果一个数字只出现了一次,那么其贡献过的相应位置的1的总个数绝对不可能是三的倍数。最后将该列模3得到1后,右移相应位,可以转变成2进制上的相应位置为1。
int singleNumber(vector<int>& nums) { int bit = 32, res = 0, count; // int型为32位整数 for(int i = 0; i < bit; i ++) { count = 0; for(int j = 0; j < nums.size(); j ++) { count += ( nums[j] >> i ) & 1; // 上一次的移位本次是不会记录的 因此 每次都是移动i位 /* 我之前是count+=(nums[j]&1); nums[j] >> 1; 这样显示是不行的。nums[j]的移动不可能保存到下一轮。所以是用i记录遍历到的位数 真的是太牛逼了- -。 */ } if(count % 3 == 1) res += (1 << i); } return res; }
leetcode.476 数字的补数
题目:给定一个正整数,输出它的补数。补数是对该数的二进制表示取反。
int findComplement(int num) { int res = 0, bit = 0; while(num) { res += (!(num & 1) << bit); num >>= 1; bit++; } return res; }
知识点和代码均学习于Acwing: https://www.acwing.com/activity/
来源:https://www.cnblogs.com/recoverableTi/p/12248052.html