1,异或运算的规则:
a) 0 xor 0 = 0
b) 0 xor 1 = 1
c) 1 xor 0 = 1
d) 1 xor 1 = 0
2, 异或运算的性质:
a) a xor a = 0
b) (a xor b) xor c = a xor (b xor c)
c) IF a xor b = c THEN a xor c = a xor (a xor b) = (a xor a) xor b = b
3, 异或的应用
Q1: 一个数组,除其中一个元素(如下面的99),其它的都是成对出现的,如何能快速找出那99的位置
……102,102,2,2,44,44,99,23,23,11,11 ……
请参考: 参考贴子
Answer 1:
把所有数组元素全部异或一下则得到非成对出现的元素99,然后顺序查找99的位置。时间复杂度为O(n)。
此解法较通用,适合如下两种特殊情况:
a),如……102,102,2,2,2, 2,44,44,99,23,23,11,11 ……(连续但存在相同元素)
b),如...... 102,2,44,23,11,99,11,23,44,2,102......(配对但不连续)
若数据无素不会出现3(a)和(b)中情况,那么可以采用一种更高效的算法:
Answer 2:
折半查找。
若数组a的元素个数为(n+1),则n+1必为奇数。数组a的序号为0到n。
left = 0; right = n; m = (left+right)/2;
int find99(left,right);
m = (n+0)/2,
IF: m为偶数,也即m两边的数量都为偶数,分别判断a[m]与a[m-1]、a[m+1]的值,若与a[m-1]相等,则99必在左侧,那么接下来就find99(left,m-1)。若与a[m+1]相等,则99必在右侧,那么find99(m+1,right)。若都不相等,则a[m] == 99,return m。
ELSE: 若m为奇数,也即m两边的数量都为奇数,分别判断a[m]与a[m-1]、a[m+1]的值,若与a[m-1]相等,则99必在右侧,find99(m+1,right)。若与a[m+1]相等,则99必在左侧,find99(left,m-1)。若都不相等,则a[m] == 99,return m。
Q2:一个很大的数组,里面有两个数只出现过一次,其他数都出现过两次,把这两个数找出来
ref :参考贴子
Answer 1:
在题目给出的很大的数组中,除要找的两个不同的数字外,其它的数字都是成对出现的,根据上面说到的两个相同的数字的异或其结果为0。因此,如果将整个数组中的元素进行异或,所得到的结果应该是所求的那两个不成对的数字的异或结果。
假定数组中两个不同的数字是95 ^ 99,则其异或的结果是0111100b,其中有4位是1,这表明这两个数字的二进制表示中有4位是不同的。(从右往左数) 它们分别是第3、4、5、6这4位,于是我们只需要
将数组中所有元素中第6位为1的元素和0111100b异或,
or,将数组中所有元素中第5位为1的元素和0111100b异或,
or,将数组中所有元素中第4位为1的元素和0111100b异或,
or,将数组中所有元素中第3位为1的元素和0111100b异或。
就可以得到所求之两个数字中的一个数字。
不妨以上面最后一条规则为例来进行说明:数组元素中第3位为1的数字,除所求的两个数字之外,都是成对出现的,它们所产生异或的结果肯定是0。而所求的那两个数字当中只有一个数字的第3位1。不妨假定这个数字是a(此时未知),另外一个要求的数字是b(此时未知)。很明显,将a (此时未知)和0111100b异或就可以得到b (此时已知),再用0111100b和已经求出来的b (此时已知) 进行异或就可以得到a (此时已知)。比如上面的95的第3位为1,所以用95 ^ 0111100b = 1011111b ^ 0111100b = 1100011b = 99,再用99 ^ 0111100b = 1100011b ^ 0111100b = 1011111b = 95。