异或相关操作

  • 什么是异或操作
  • 异或的性质
  • 使用异或实现交换操作
  • 使用异或解决相关算法问题
  • 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),这些法则与加法是相同的,只是不带进位。

使用异或操作不用申请额外的空间

异或的性质

  1. 0^N = N
  2. N^N = 0
  3. 满足交换律和结合律,即a异或b = b异或a, (a异或b)异或c = a异或(b异或c)
  4. 同一批数异或所得的结果相同

使用异或实现交换操作

python 异或加密 python中异或运算_python


需要注意的是:两个数在内存里的地址一定不能一样

如果是在数组里实现交换操作,如下图

python 异或加密 python中异或运算_空间复杂度_02


一定要保证 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)

输出结果为

python 异或加密 python中异或运算_空间复杂度_03

2. 假设有一个arr数组,在这个数组中,有两个数出现了奇数次,其余都出现了偶数次,请你找出这个数。要求时间复杂度为O(N),空间复杂度为O(1)。

由于这个可能有点绕,我就在纸上写出整个过程,尽量详细且清晰

python 异或加密 python中异或运算_数组_04


代码实现如下:

#有两个数出现了奇数次,找出这两个数
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))

输出为:

python 异或加密 python中异或运算_数组_05

关于rightOne = med & (~med+1)这句代码,它的目的就是找到二进制位表示中的最右边的1,举例如下

med : 1010111100
 ~med : 0101000011 取反码
 ~med+1 : 0101000100
 med & ~med+1 : 0000000100

关于异或操作本人目前就理解这么多,如有错误请多多包涵,谢谢指导。