之前也是学了很多数据结构与算法,不过一直没有注重位运算这方面,没想到它还有这么神奇的一面,很多不可能的事情忽然就发生了。接下来让我们认真学习一下吧!
1.不使用辅助空间交换两个变量的值
知识点:A ^ A=0,A ^ 0 = A
分析:假设x=a,y=b;那么需要交换x与y的值
1) 令x= x ^ y =a ^ b,那么要想让y=a,可以利用A ^ A = 0的特性将x中的(a ^ b)消去b,即a ^ b ^ b (此时 x= a ^ b,y = b)
2) 那么就可以令 y = x ^ y = a ^ b ^ b = a ,至此y得到了原先x的值,
接下来只需要通过位运算使得x=b即可 (此时x = a ^ b,y = a )
3)令x= x ^ y = a ^ b ^ a =b (至此 x = b ,y = a)
利用Java进行代码实现:
int x=5,y=8;
x=x^y; // 此时 x = 5 ^ 8 y = 8
y=x^y; // 此时 x = 5 ^ 8 y=5 ^ 8 ^8 = 5
x=x^y; // 此时 x = 5 ^ 8 ^ 5 = 8 y = 5
结论:异或可以去除重复的成对元素
2.不使用辅助空间只访问一次数组就找出重复的那个元素
题目:数组长度1001,1 ~ 1000中有一个数出现2次,其他都出现一次,在不使用辅助空间
且数组中的每个元素只能访问一次的情况下找到这个重复的元素
知识点:A ^ A =0 ,A ^ 0 = A
分析:假设重复的那个元素为k,如果将数组中所有元素都进行异或,那么将得到如下式子:
S1 = 1 ^ 2 ^ 3 . . . ^ k ^ k. . . ^ 1000
那么可以利用A ^ A = 0 的性质,给上式子中的每一次数都进行再次异或,即
S2 = ( 1 ^ 2 ^ 3 . . . ^ k ^ k. . . ^ 1000 ) ^ ( 1 ^ 2 ^ 3 . . . ^ k . . . ^1000 )
= ( 1 ^ 1 ^ 2 ^ 2 ^ 3 ^ 3 . . . ^ k ^ k ^ k . . . ^ 1000 ^ 1000 )
= k
Java代码实现如下:
//数组为arr,数组长度为1001,数组为1~1000
int getRepeatNumber(int[]arr){
//1.让数组中每一个数据都进行异或
int res=arr[0];
for(int i=1;i<1001;i++){
res^=arr[i];
}
//2.让异或后的结果再分别于1~1000进行异或
for(int i=1;i<=1000;i++){
res^=i;
}
return res;
}
结论:异或可以去除重复的成对元素
3.用一条语句判断整数是否为2的整数次方
知识点:number & (number-1) 的结果去除了number二进制中最后那位1
知识点说明:如果 number = 0b11100,那么number-1=0b11011
number : 1 1 1 0 0
number-1 : 1 1 0 1 1
number & (number-1) : 1 1 0 0 0
可以看出number的最后一位1已经被除去,而2的整数次幂在二进制状态下只包含1个1位,如:
2 ^ 0 : 1
2 ^ 1 : 1 0
2 ^ 2 : 1 0 0
分析:只需要判断 number & (number-1)的结果是否为0即可
Java代码实现如下:
boolean is2Pow(int number){
return (number & (number - 1)) == 0
}
结论:number & (number -1) 可以去除二进制最后的1
4.不使用辅助空间找到只出现1次的那个数
题目:数组中只有一个数出现了1次,其他的数都出现了k次,找出只出现一次的数
知识点:k个number在k进制下做不进位加法运算得到的结果为0
这个知识听起来有点绕,不过别急,听小小李一点点分析之后你一定觉得很简单!
知识点解析:
1)不进位加法运算:
如 8+5=13 省去进位的1 即 8+5=3即为不进位运算
2)k个number在k进制下做不进位加法:
如十进制下:10个8相加=80丢弃进位的8,即8+8+...+8=0
分析: 用这个结论将数组中所有元素进行不进位加法运算的结果为出现1次的那个数,
出现k次的数做不进位加法之后结果为0,所以除了只出现1次的那个数,其他的数
相加的结果为0
Java代码实现:
//找到只出现1次的那个数
int getMeetOneNumber(int[]arr,int k){
char[][]kRadix=new char[arr.length][];
int maxLen=0;
//将数组中的数转换为k进制并反转
for (int i = 0; i < arr.length; i++) {
kRadix[i]=new StringBuffer(Integer.toString(arr[i],k)).reverse().toString().toCharArray();
if (kRadix[i].length>maxLen)
maxLen=kRadix[i].length;
}
int[]resArr=new int[maxLen];
//将数组中所有数对应位进行不进位加法运算
for (int i = 0; i < kRadix.length; i++) {
for (int j = 0; j < resArr.length; j++) {
if (j<kRadix[i].length)
resArr[j]= (resArr[j] + kRadix[i][j]-'0')%k;
}
}
//最终resArr里面储存的就是只出现1次的那个数的k进制,转换为10进制返回即可
int res=0;
for (int i = 0; i < resArr.length; i++) {
res+= (resArr[i]%k)*Math.pow(k,i);
}
return res;
}
结论:k个number在k进制下做不进位加法运算得到的结果为0
总结
结论1:异或可以去除重复的成对元素
结论2:number & (number -1) 可以去除二进制最后的1
结论3:k个number在k进制下做不进位加法运算得到的结果为0