若是把一个数n以二进制数的形式表示的话,咱们只须要判断最后一个二进制位是1仍是0便可。若是是1,则表明奇数,不然为偶数。代码以下:java
if(n & 1 == 1){ // n是奇数 }
x = x ^ y; // (1) y = x ^ y; // (2) x = x ^ y; // (3)
咱们都知道两个相同的数异或以后的结果为0,即 n ^ n = 0,而且任何数与0异或以后等于它自己,即 n ^ 0 = n。函数
因而咱们把(1)中的x代入(2)中的x,有:y = x ^ y = (x ^ y) ^ y = x ^ ( y ^ y) = x ^ 0 = x,这样x的值就赋给了y。code
对于(3),推导以下:x = x ^ y = (x ^ y) ^ x = (x ^ x) ^ y = 0 ^ y = y,这样y的值就赋给了x。class
异或运算支持运算的交换律和结合律。遍历
给你一组整型数据,这些数据中,其中有一个数只出现了一次,其余的数都出现了两次,让你来找出一个数二进制
这道题可能不少人会用一个哈希表来存储,每次存储的时候,记录下某个数出现的次数,最后遍历哈希表找出只出现了一次的次数。这种方式的时间复杂度是O(n),空间复杂度也为O(n)了。数据
其实这道题也能够进行位运算,,咱们能够把这一组整型数全都异或,因为两个相同的数异或的结果为0,一个数与0异或的结果为其自身,因此异或的所获得的结果就为只出现了一次的数。例如这组数据是:1, 2, 3, 4, 5, 1, 2, 3, 4。其中 5 只出现了一次,其余都出现了两次,把他们所有异或一下,结果以下:移动
1 ^ 2 ^ 3 ^ 4 ^ 5 ^ 1 ^ 2 ^ 3 ^ 4 = (1 ^ 1) ^ (2 ^ 2) ^ (3 ^ 3) ^ (4 ^ 4) ^ 5 = 0 ^ 0 ^ 0 ^ 0 ^ 5 = 5时间
代码以下:while
int find(int[] nums){ int tmp = nums[0]; for(int i = 1;i < nums.length; i++) tmp ^= arr[i]; return tmp; }
求解 2 的 n 次方,而且不能使用系统自带的 pow 函数
不少人看到这个题可能以为让n个2相乘就好了,若是这么作的话,时间复杂度为O(n)了。那么如何用位运算来作呢?
好比n = 13,n的二进制数表示为1101,那么2的13次方能够拆解为:2 ^ 1101 = 2 ^ 0001 * 2 ^ 0100 * 2 ^ 1000。咱们能够经过 & 1和 >>1 来逐位读取 1101,为1时将该位表明的乘数累乘到最终结果。最终代码以下:
int pow(int n) { int sum = 1; int tmp = 2; while(n != 0) { if(n & 1 == 1) sum *= tmp; temp *= temp; n >>= 1; } return sum; }
例如 N = 19,那么转换成二进制就是 00010011(这里为了方便,我采用8位的二进制来表示)。那么咱们要找的数就是,把二进制中最左边的 1 保留,后面的 1 所有变为 0。即咱们的目标数是 00010000。那么如何得到这个数呢?相应解法以下:
一、找到最左边的 1,而后把它右边的全部 0 变成 1
二、把获得的数值加 1,能够获得 00100000即 00011111 + 1 = 00100000。
三、把 获得的 00100000 向右移动一位,便可获得 00010000,即 00100000 >> 1 = 00010000。
那么问题来了,第一步中把最左边 1 中后面的 0 转化为 1 该怎么才能得到呢?
代码以下:
n |= n >> 1; n |= n >> 2; n |= n >> 4;
就是经过把 n 右移而且作或运算便可获得。我解释下吧,咱们假设最左边的 1 处于二进制位中的第 k 位(从左往右数),那么把 n 右移一位以后,那么获得的结果中第 k+1 位也一定为 1,而后把 n 与右移后的结果作或运算,那么获得的结果中第 k 和 第 k + 1 位一定是 1;一样的道理,再次把 n 右移两位,那么获得的结果中第 k+2和第 k+3 位一定是 1,而后再次作或运算,那么就能获得第 k, k+1, k+2, k+3 都是 1,如此往复下去….
最终的代码以下:
int findN(int n){ n |= n >> 1; n |= n >> 2; n |= n >> 4; n |= n >> 8 // 整型通常是 32 位,上面我是假设 8 位。 return (n + 1) >> 1; }
这种作法的时间复杂度近似为 O(1)。