在程序中适当使用位运算可以提高程序运行效率。
例如,判断程序是否为奇数
if(i % 2 == 1) // 判断i是否为奇数
可以用位运算语句进行代替
if(i & 1 == 1) // 判断数是否为奇数
还有乘2和除2的运算操作
i *= 2
i /= 2
可以由位移操作代替
i <<= 1; // 左移运算,相当于乘2
i >>= 1; // 右移运算,相当于除2
用位运算代替原始的运算操作,在操作数量级很大的情况下,可以节省相当的时间。
对于部分算法题目,我们可以从位运算的角度求解
leetcode 136 只出现一次的数字
在一个数组中找出只出现一次的一个数字,其余数字均会出现两次。
这道题目可以用位运算中的异或(^)操作求解,异或运算的原则为位相同为0,相异为1,所以两个相同的数异或为0(n^n=0),一个数和0异或操作数值不变(n^0=0^n=0),所以只要将数组中的数全部进行异或操作即可得到解。
int singleNumber(vector& nums) {
int n = 0;
for(int i=0; i
leetcode 231 2的幂
判断一个数是否为2的幂
2的幂的数字的二进制形式为1000...(n个0),该数字减1就变成了0111111(n个1),我们发现减去1后每一位都相反,所以判断他们相与(&)为0即可。
bool isPowerOfTwo(int n) {
if(n<=0)
return false;
return (((n-1)&n)==0);
}
部分试题直接考察位运算的操作
leetcode 190 颠倒二进制位
uint32_t reverseBits(uint32_t n) {
uint32_t ans=0;
int i=32;
while(i--)
{
ans <<= 1;
ans += n&1; // 复制当前n中的最后一位
n >>= 1;
}
return ans;
}
相似题目 leetcode 476 数字的补数
在部分情况下,可以使用C++的bitset库来处理位操作
#include
构建bitset时需要传入一个正整数N代表比特的位数
template class bitset;
构建bitset
bitset<8> b1; // 比特位全0 00000000
bitset<8> b2(3); // 十进制数字初始化,代表该数字的二进制 00000011
bitset<8> b3("01111001"); // 字符串初始化 01111001
bitset<8> b4("0101111001"); // 字符串初始化,如果长度超出则截取前n位 01011110
bitset<8> b5(0xa); // 十六进制数字初始化 00001010
bitset<8> b;
bitset<8> b2;
cout << b[1] << endl; // 访问第n个比特位 0
b[1] = 1;
b[2] = b[1];
cout << "修改后的b为:" << b << endl; // 00000110
// count操作
cout << "b中1的个数为:" << b.count() << endl; // 2
// size
cout << "b的长度为:" << b.size() << endl; // 8
// 求0
cout << "b中0的个数为:" << (b.size() - b.count()) << endl; // 6
// test返回bitset第n位的是否为1
cout << b.test(0) << ' ' << b.test(1) << endl; // 0 1
// any bitset中是否有任意一位为1
cout << b.any() << endl; // 1
cout << b2.any() << endl; // 0
// none bitset是否全为0
cout << b.none() << endl; // 0
cout << b2.none() << endl; // 1
bitset<4> b; // 0000
// set
cout << b.set() << endl; // 全部设置为1 1111
cout << b.set(2,0) << endl; // 将第2位设置为0 1011
cout << b.set(2) << endl; // 设置第2位为1 1111
// reset
cout << b.reset(1) << endl; // 将第1位设置为0 1001
cout << b.reset() << endl; // 全部设置为 0000
// flip
cout << b.flip(2) << endl; // 第2位取反 0100
cout << b.flip() << endl; // 全部位取反 1011
bitset可以相当简化的bool数组,但是占用的内存更加少,因为8个比特位才占一个字节
bitset<100000> b;
bool b2[100000];
printf("%d\n", sizeof(b));
printf("%d\n", sizeof(b2));
输出结果
12500
100000
不过bitset的缺点也是很明显的,在定义时必须确定变量的代销,不能采用动态的值,长度也不能像vector那样动态变化,不过需要大长度布尔型数组时,可以在算法题中采用bitset节约内存,例如筛法求素数中的数组,第n位上的值代表第n个数是否为素数
bitset<100001> b;
b.set(); // 全部设置为1
b.reset(0); // 第0位设置为0
b.reset(1); // 第1位设置为0 代表1不是素数
for (int i = 2; i
输出n位二进制字符串
bitset可以用来偷懒地输出二进制字符串
bitset<8> b(12);
string s = b.to_string(); // 转换为字符串 00001100
cout << s << endl;
cout << bitset<8>(011) << endl; // 八进制初始化 00001001
cout << bitset<8>(0xa) << endl; // 十六进制初始化 00001010
利用bitset解题
leetcode 762 二进制表示中质数个计算置位
(这里仅仅为了演示bitset用法)
int countPrimeSetBits(int L, int R) {
bitset<32> b;
b.set(2);
b.set(3);
b.set(5);
b.set(7);
b.set(11);
b.set(13);
b.set(17);
b.set(19);
b.set(23);
b.set(29);
b.set(31);
int c=0;
for(int i=L; i<=R;i++)
{
bitset<32> bits(i);
if(b[ bits.count() ]) {
c++;
}
}
return c;
}
http://www.cplusplus.com/reference/bitset/bitset/