位运算符
符号 | 解释 |
---|---|
& | 按位与 |
按位或 | |
~ | 按位异或 |
<< | 左移 |
>> | 右移 |
原码、补码、反码
补码=原码取反+1
例如,-5 二进制数-101; 原码10000101; 反码11111010; 补码11111011
妙用
判断奇偶数
左移一位相当于乘以2,右移一位相当于除以2
template<class T>
int Binary_Search(T *x, int N, T keyword)
{
int low = 0, high = N-1,mid;
while(low <= high)
{
mid = (low + high)>>1;//使用位运算代替乘除2可以提高代码效率
if(x[mid] == keyword)
return mid;
if(x[mid] < keyword)
low = mid + 1;
else
high = mid -1;
}
return -1;
}
统计二进制数字中1的个数
相当于JAVA的Integer.bitCount()
int bitCount(int num)
{
int sum = 0;
while(num > 0)
{
sum += num &1;
num = num >>1;
}
return sum;
}
Swap交换两个数值的函数
利用位运算可以不用开辟新空间实现交换数值功能
原理是利用异或运算的特性:任意数和自身异或结果为0,0和任意数异或的结果还是其本身
a = a ^ b,普通的异或
b = b ^ a = b ^ a ^ b,因为 b ^ b = 0,故 b = a ^ 0,即 b = a;
a = a ^ b ,因为a在第一行重新赋值,所以a = a ^ b ^ a = b,完成了数值交换
void Swap(int& a, int& b)
{
a ^= b
b ^= a
a ^= b
}
寻找数据列表中只出现一次的数
有一个数据列表,只有一个数出现了1次,其余N个数都出现了2次。如何不利用额外空间而且在O(n)时间内找到这个只出现一次的数?
还是利用异或的特性
int singleNumber(vector<int>& nums)
{
if(nums.empty()) return 0;
int res = 0;
for(int i : nums)
{
res = res ^ i;
}
return res;
}
检查第i位是否为1
例如要检查数值num的第3位是否为1,把1左移3位得到4(100),num & 4的返回值的就是结果
bool isOne(int num, int i)
{
return num & (1<<i);
}
把第i位改为1
例如要把数值num的第3位改为1,把1左移3位得到4(100),num | 4的返回值的就是结果
int alterOne(int num, int i)
{
return num | (1<<i);
}
另外,num|1相当于num+1;通常用num|1-1求得num最近的偶数
把第i位改为0
例如要把数值num的第3位改为0,把1左移3位得到4(100),num & ~4的返回值的就是结果,因为 ~4的二进制是011
int alterZero(int num, int i)
{
return num & ~(1<<i);
}
把第i位取反
例如要把数值num的第3位取反,把1左移3位得到4(100),num ^ 4的返回值的就是结果
int alterOpposite(int num, int i)
{
return num ^ (1<<i);
}
取出一个数的最后一个1
把num左移1位后再进行异或,就会发现如果原数第i位是0,异或就变成1,否则变成0
利用二进制来枚举子集
给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
输入: nums = [1,2,3]
输出:[[3],[1],[2],[1,2,3],[1,3],[2,3],[1,2],[]]
vector<vector<int>> subsets(vector<int>& nums)
{
vector<vector<int>> res;
int len=(1<<nums.size());
for(int i=0;i<len;++i)
{
vector<int> cur;
for(int j=0;j<nums.size();++j)
{
if((i>>j)&1==1) cur.push_back(nums[j]);
}
res.push_back(cur);
}
return res;
}