算法模板-----位运算
Posted 栋次大次
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法模板-----位运算相关的知识,希望对你有一定的参考价值。
位运算符
single-number
single-number-ii
single-number-iii
number-of-1-bits
counting-bits
reverse-bits
bitwise-and-of-numbers-range
位运算符
运算符 | 描述 | 规则 |
---|---|---|
& | 与 | 两个位都是1结果为1 |
| | 或 | 两个位都是0结果为0 |
^ | 异或 | 相同为0,相异为1 |
~ | 取反 | 原位取反 |
<< | 左移 | 二进制各位全部左移若干位,高位丢弃,低位补0 |
>> | 右移 | 二进制各位全部右移若干位,对无符号数,高位补0;有符号数,各编译器处理方法不一样,有补符号位(算术右移),有补0(逻辑右移) |
常见操作
a=0^a=a^0
0=a^a
上式推出:a=a^b^b
交换两个数,不必使用临时变量
a=a^b
b=a^b
a=a^b
移除最后一个1
a=n&(n-1)
获取最后一个1
diff=(n&(n-1))^n
或者
diff=x&(-x) # -x=~x+1
常见题目
给定一个非空整数数组,除了某个元素只出现一次外,其他每个元素均出现两次
思路:利用异或
int singleNumber(vector<int>& nums)
// 两个相同的数异或为0 相异为本身
int res = 0;
for(auto n : nums)
res = n ^ res;
return res;
给定一个非空数组,除了某个元素只出现一次外,其余每个元素均出现三次。
思路:对于出现三次的数字,各二进制出现的次数都是三的倍数。因此,统计所有数字的各二进制位中1出现的次数,并对3求余,结果则为只出现一次的数字。
//位状态机。推荐使用这种方法,很巧妙。
int singleNumber(vector<int>& nums)
int a = 0, b = 0;
for(int num : nums)
a = (a ^ num) & (~b);
b = (b ^ num) & (~a);
return a;
// 解法二,遍历统计每位
int singleNumber(vector<int>& nums)
int res = 0;
for(int i = 0; i < 32; i++)
int cnt = 0;
for(auto x : nums)
cnt += (x>>i)&1;
res |= (cnt%3)<<i;
return res;
给定一个整数数组,其中恰好有两个元素只出现一次,其余所有元素均出现两次。找出值出现一次的两个元素。
vector<int> singleNumber(vector<int>& nums)
int s = 0;
for(auto n : nums)
// 去除出现两次的数
s = s ^ n;
s = s & (-s); // 保留最右边的1
vector<int> res(2, 0);
for(auto n : nums)
if(n & s)
res[0] ^= n;
else
res[1] ^= n;
return res;
输入一个无符号整数,返回其二进制表达式中为1的个数(汉明重量)
int hammingWeight(uint32_t n)
int count = 0;
while(n > 0)
n = n & (n-1); //移除最后一个1
count++;
return count;
给定一个非负整数num。对于0<=i<=num范围内中的每个数字i,计算其二进制中的1的数目并将它们作为数组返回。
vector<int> countBits(int num)
vector<int> res;
for(int i = 0; i <= num; i++)
res.push_back(hammingWeight(i));
int hammingWeight(int num)
int count = 0;
while(num != 0)
num &= (num - 1);
count++;
return count;
另一种动态规划解法:让上一个缺1的元素+1即可
vector<int> countBits(int num)
vector<int> res(num + 1);
for(int i = 1; i <= num; i++)
res[i] = res[i & (i-1)] + 1;
return res;
颠倒给定的32位无符号整数的二进制位
uint32_t reverseBits(uint32_t n)
uint32_t res = 0;
int pow = 31; //记录位置
while(n != 0)
//取出最后一位
res += (n & 1) << pow;
n >>= 1;
pow--;
return res;
给定范围[m,n], 其中0<=m<=n<=2147483647,返回此范围内所有数字的按位与(包含m、n)
思路:1. 迭代进行与操作(可能会超时)2. 寻找公共前缀
//解法1
int rangeBitwiseAnd(int m, int n)
while(m < n)
n &= n -1;
return m & n;
// 解法二
int rangeBitwiseAnd(int m, int n)
int count = 0;
while(m != n)
m >>= 1;
n >>= 1;
count++;
return n <<= count;
以上是关于算法模板-----位运算的主要内容,如果未能解决你的问题,请参考以下文章