什么是位运算
因为在计算机的世界里,目前它只认识0和1.程序中的所有数在计算机内存中都是以二进制的形式储存的。位运算说穿了,就是直接对整数在内存中的二进制位进行操作。由于位运算直接对内存数据进行操作,不需要转成十进制,因此处理速度非常快。
位运算
按位与 a & b
按位或 a | b
按位异或 a ^ b
按位取反 ~a
左移 a << b
带符号右移 a >> b
带符号右移 无符号右移 a>>> b。
用位运算能解决的题目
1.一个数组中有一个数出现了奇数次,其他的数都是偶数次。求出这个数
思路
两个相同的数异或之后为0,也就是说成对出现的数异或之后都是0.所以整个数组异或之后的结果就是那个出现奇数次的数。
代码
public static void printOddTimesNum(int[] arr){
int eor =0;
for (int i =0;i<arr.length;i++){
eor = eor^arr[i];
}
System.out.println(eor);
}
2.升级一下,数组中有两种数出现了奇数次,求出这两个数
思路
假设这两个数是 a和b,根据上一题的思路,整个数组异或之后,得出的就是 a^b.暂且设置结果为eor。
那么怎么分离出a和b 呢?
可以把eor 中最右侧的二进制的1 作为分离因子,因为这个1 要么在a中,要么在b中。
遍历数组,把相同二进制中为1的数进行异或,这样就得到了 a或者是b。
最后 a^eor 就得到了b。
求一个数二进制中最右侧的1
//求一个数二进制最低位的1
public static int getRightOne(int targetNum){
int res = targetNum & ((~targetNum)+1);
//直接可以这样写
res = targetNum & (-targetNum);
return res;
}
引出另外一个题目,求一个数中二进制位有多少个1
//求一个二进制数据中1的个数
public static int bit1counts(int num){
int count =0;
while (num!=0){
int rightOne = getRightOne(num);
count++;
num^=rightOne;
}
return count;
}
题目2的代码
public static void printOddTimesNums2(int[] arr){
int eor =0;
//先求出 这两个数异或的结果
for (int i=0;i<arr.length;i++){
eor^=arr[i];
}
// 因为a 和b 是两种数
//获取异或结果的最右边的1
int rightone = getRightOne(eor);
//分离出其中一个数
int a = 0;
for (int i=0;i<arr.length;i++){
if ((arr[i] & rightone) !=0){
a^=arr[i];
}
}
System.out.println("a="+a+" b="+(a^eor));
}