异或相关操作
- 什么是异或操作
- 异或的性质
- 使用异或实现交换操作
- 使用异或解决相关算法问题
- 1. 假设有一个arr数组,在这个数组中,有一个数出现了奇数次,其余都出现了偶数次,请你找出这个数。要求时间复杂度为O(N),空间复杂度为O(1)。
- 2. 假设有一个arr数组,在这个数组中,有两个数出现了奇数次,其余都出现了偶数次,请你找出这个数。要求时间复杂度为O(N),空间复杂度为O(1)。
在相关编程语言(c,java,python等)中,我们经常会看到异或操作,异或和加减乘除都属于一个性质,但是运算速度比加减乘除等运算要快的多的多,当在算法中遇到对时间复杂度有要求的,可以尝试一下使用异或操作是否可以解决。
什么是异或操作
如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。
异或也叫半加运算或者无进位相加,其运算法则相当于不带进位的二进制加法:二进制下用1表示真,0表示假,则异或的运算法则为:0⊕0=0,1⊕0=1,0⊕1=1,1⊕1=0(同为0,异为1),这些法则与加法是相同的,只是不带进位。
使用异或操作不用申请额外的空间
异或的性质
- 0^N = N
- N^N = 0
- 满足交换律和结合律,即a异或b = b异或a, (a异或b)异或c = a异或(b异或c)
- 同一批数异或所得的结果相同
使用异或实现交换操作
需要注意的是:两个数在内存里的地址一定不能一样
如果是在数组里实现交换操作,如下图
一定要保证 i 和 j 不能相等,其实在进行交换时最好还是使用新定义一个temp作为中间存储的方法来实现,上述的交换方法可以当做理解异或操作,不建议使用,因为你可能无法确保两个数在内存里的地址一样。
使用异或解决相关算法问题
1. 假设有一个arr数组,在这个数组中,有一个数出现了奇数次,其余都出现了偶数次,请你找出这个数。要求时间复杂度为O(N),空间复杂度为O(1)。
首先定义eor = 0
;我们让eor遍历异或整个数组,遍历后,eor的值即为出现奇数次的那个数字。
eor = eor^a
eor = eor^b
eor = eor^c
……
具体实现代码如下:
eor = 0
arr = [1,3,1,2,1,1,5,3,2]
for i in range(len(arr)):
eor ^= arr[i]
print(eor)
输出结果为
2. 假设有一个arr数组,在这个数组中,有两个数出现了奇数次,其余都出现了偶数次,请你找出这个数。要求时间复杂度为O(N),空间复杂度为O(1)。
由于这个可能有点绕,我就在纸上写出整个过程,尽量详细且清晰
代码实现如下:
#有两个数出现了奇数次,找出这两个数
med,med1 = 0,0
arr_1 = [1,3,1,2,1,5,3,2]
for i in range(len(arr_1)):
med ^= arr_1[i]
# eor = a^b
# eor != 0
# eor的二进制位中必有一个位置为一,我们找出最右的位置
rightOne = med & (~med+1) #提出最右的1
for i in range(len(arr_1)):
if((rightOne & arr_1[i])==rightOne): #写!=也可,目的就是将数组分为两部分
med1 ^= arr_1[i]
print('出现奇数次的两个数为: {}和{}。'.format(med1,med1^med))
输出为:
关于rightOne = med & (~med+1)
这句代码,它的目的就是找到二进制位表示中的最右边的1,举例如下
med : 1010111100
~med : 0101000011 取反码
~med+1 : 0101000100
med & ~med+1 : 0000000100
关于异或操作本人目前就理解这么多,如有错误请多多包涵,谢谢指导。