【数据结构与算法】(七)异或法

 定义:

       异或是基于二进制的位运算,用符号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)

 

  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值