1.一些常规的计算:
x ^ 0s = x x & 0s = 0 x | 0s = x
x ^ 1s = ~x x & 1s = x x | 1s = 1s
x ^ x = 0 x & x = x x | x = x
^ (异或)----- 相同的为0,相异的为1
2.位运算实用的技巧
(1) x & (x-1)
可以消去x中(二进制状态下)的最后面的 1 .
(2) 求数组的子集
[ 1 , 2 , 3 ]
n(元素的个数) N=2^n (二的n次方)
子集为从0到N-1对应下的二进制:
0 000 {}
1 001 {1}
2 010 {2}
3 011 {1,2}
4 100 {3}
5 101 {1,3}
6 110 {2,3}
7 111 {1,2,3}
#include<iostream>
using namespace std;
int main()
{
int a[3] = { 5,6,7 };
int n = pow(2, 3);
for (int i = 0; i < n; i++)
{
if (i == 0) {
cout << "空集";
continue;
}
int x = i;
int count = 0;
cout << " ";
while (x)
{
if (x & 1) {
cout << a[count];
}
x >>= 1;
count++;
}
}
return 0;
}
空集 5 6 56 7 57 67 567
C:\Users\17281\source\repos\Project69\Debug\Project69.exe (进程 14144)已退出,代码为 0。
按任意键关闭此窗口. . .
(3) a^b^b=a
例1:数组中只有一个数出现过一次,其余数出现过两次,求这个出现一次的数
解:从头异或到底最后得到的数就答案
例2:数组中只有二个数出现过一次,其余数出现过两次,求这两个数。
问题
Given [1,2,2,3,4,4,5,3] return 1 and 5
解题思路
有了第一题的基本的思路,我们不妨假设出现一个的两个元素是x,y,那么最终所有的元素异或的结果就是res = x^y。并且res!=0,那么我们可以找出res二进制表示中的某一位是1,那么这一位1对于这两个数x,y只有一个数的该位置是1。对于原来的数组,我们可以根据这个位置是不是1就可以将数组分成两个部分。求出x,y其中一个,我们就能求出两个了。
#include<iostream>
using namespace std;
int main()
{
int a[8] = { 1, 2, 2, 3, 4, 4, 5, 3 };
int res = 0,ans,count=0,x=0,y=0;
for (int i = 0; i < 8; i++)
{
res = res ^ a[i];
}
ans = res;
//找到最右边的1所在的二进制位数
while (1)
{
if (res & 1)
{
break;
}
count++;
res >>= 1;
}
for (int i = 0; i < 8; i++)
{
if ((a[i] >> count) & 1)
x = x ^ a[i];
}
y = ans ^ x;
cout << x <<" "<< y;
}
例3:数组中只有一个数出现过一次,其余数出现过3次,求这个出现一次的数
问题
Given [1,1,2,3,3,3,2,2,4,1] return 4
解体思路
对于每一个二进制位,如果只出现一次的数在该二进制位为1,那么这个二进制位在全部数字中出现次数无法被3整除。
#include<iostream>
using namespace std;
int bit[32];//用于存储各位二进制下对应的1的总数;
int main()
{
int res = 0;//记录答案
int a[10] = { 1,1,2,3,3,3,2,2,4,1 };
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 32; j++)
{
bit[j] += ((a[i] >> j) & 1);
}
}
for (int i = 0; i < 32; i++)
{
if (bit[i] % 3 == 1)
res = res + 1 << i;
}
cout << res;
}
(4) 可以判断一个数的奇偶性:
判断该数二进制下最后一位是否为1即可
例:3 -> 011, 6->110
(5) 可以用于交换两个数 交换 X ,Y;
常规的算法在此不写
位运算三步:
X=X ^ Y
Y=X^Y
X=X^Y
(6) 或:可以把两个数中的1全部保存下来,可能这么说有点抽象,下面举个实例:
例如将 abce 用 10111表示(按位表示)
int q=0;
s="abce"
for ( int i=0,i<strlen(s);i++)
{
q=q | 1<<(s[i]-'a');
}
cout<<q;
(7)
判断一个数 x 是否为 2 的整数幂
法一:x & (-x) == x; 其中 x & (-x) 等于x的二进制表示里最右边一个1
法二:看一下x在二进制状态下表示是否只有一个1 x&(x-1) 可以消去x二进制下最后面的一位1
如果进行一次操作 x&(x-1) == 0 的话该数就为2的整数幂。
判断一个数 x 是否为 4的整数幂
如果这个数也是 4 的次方,那二进制表示中 1 的位置必须为奇数位。我们可以把 n 和二进制 的 10101...101(即十进制下的 1431655765)做按位与,如果结果不为 0,那么说明这个数是 4 的 次方。
bool isPowerOfFour(int n) {
return n > 0 && !(n & (n - 1)) && (n & 1431655765);
}