定义:
异或是基于二进制的位运算,用符号XOR或者^表示,对符号两边的数的二进制进行运算,相同为0,不同为1。简单理解就是不进位加法。
性质:
(1)交换律 : a^b = b^a
(2)结合律 : a^b^c = a^(b^c)
(3)x^x = 0 x^0 = x
(4)自反性:a^b^b = a (最重要的性质)
(5)如果a^b = c 那么a^c = b ,b^c = a (最最牛逼的一点)
用途一:交换两个变量的值,不通过中间元素
tmp = a
a = b
b = tmp
但是通过异或可以直接交换:
a = a^b
b = b^a
a = a^b
分析:
a = a^b #式1
b = b^a = b^(a^b) = b^b^a = a #式2 将式1代入
a = a^b = (a^b)^(a) = a^a^b = b #式3 将式1式2代入
用途二:使某些特定位翻转
比如把数10100001的第2位和第3位翻转,则可以将该数与00000110进行按位异或运算。
10100001^00000110 = 10100111
用途三:找出数组中唯一重复元素
例:数字1-1000放在含有1001个元素的数组中,只有唯一一个元素重复,其他元素只出现一次,设计一个算法找出它,要求每个元素只能访问一次。
方法一:累加求和法:把数组中的元素统统加起来,然后减去1-1000的和,剩下的就是那个重复的元素。
评价:时间复杂度O(n),空间复杂度O(1)。完成1-1000当然没问题,但是如果换成很大的数,就可能会溢出了。
方法二:异或法:
#假设重复的元素为X(突出表示为大写)
(a^b^c^d^e...X^X^y^z) ^ (a^b^c^d^e...X^y^z)
= (a^a)^(b^b)...(z^z) ^ (X^X^X)
= 0^0^0...^0 ^ X
= X
代码如下:
def findDup(array):
if array == None:
return
lens = len(array)
i = 0
result = 0
while i < lens:
result ^=array[i]
i+=1
j = 1
while j < lens:
result^ = j
j+=1
return result
用途四:找出数组中缺失的元素
例:给定n-1个整数组成的未排序数组序列,其元素都是1到n中的不同整数,求找出数组中缺失整数的线性时间方法。
方法一:求和法(同上)
n个数的和减去n-1个数的和就是缺失的那个数。
方法二:异或法(同上)
用途五:如何找出数组中出现奇数次的数
第一步:原理同上面一样,所有数都按位异或完以后,出现偶数次的数都变成了0,最后异或的结果就是这两个出现奇数次的数直接异或的结果。假设 a b 是奇数次出现的两个数,c为所有数异或的结果,即:
a^b^d^d^...z^z =a^b = c
第二步:
已经知道c,就知道c的哪些位上是1,然后在原来的数组中,把这些位上是1的所有数都跟c异或,其实就是把a或者b中的某个数和c异或,结果就是另一个数,已经知道c和另一个数,然后把c和另一个数异或就是剩下的数。
原理:c中第n位为1,表示a或b中其中一个数的该位为1,而其余一个必定不是1,所以相当于把c和a或b中的其中一个异或,结果就是另一个数。
代码:
def get2Num(arr):
if arr ==None or len(arr)<1:
print("参数不合理")
return
result = 0
tmpresult = 0
position = 0
i =0
while i<len(arr):
result^= arr[i]
i+=1
tmpresult = result #暂存数组所有数异或的结果
i = result
while i&1 ==0: #判断该位是不是0,如果是0 就右移扔掉,一直找到第一位不是0
position+=1 #的位(也就是第一个1所在的位),把它记为position位
i=i>>1
i = 1
while i<len(arr):
if ((arr[i]>>position)&1) == 1: #把数组中,所有满足第position位为1的数,都和
result =result ^arr[i] #result进行异或
i+=1
print(result)
print(result^tmpresult)