异或问题总结


前言

通常来讲,我们说异或问题就是:相同为0,不同为1
左神说,我们可以将异或问题看为无进位相加
举个例子:
6^7
6 的二进制表示为110,7的二进制表示为111,通过“相同为0,不同为1”的口诀得到001。
无进位相加我们可以得到,0+1=1,1+1=2写0,此时不进位,然后1+1=2写0,此时不进位,也可以得到001。


一、异或运算的性质

1. 0^N == N , N ^ N == 0

2. 异或运算满足交换律和结合律

根据第二条性质可知,不管顺序,位置,同一批数异或运算结果一定是一样的。

二、练习题

1.不用额外变量交换两个数

class XOR():
    # 不用额外变量交换两个数
    def swap(self, a, b):
        a = a ^ b
        b = a ^ b
        a = a ^ b

# 代码解释:
假设a=6,b=5
第一步:a = a ^ b 也就是 a = 6 ^ 5
第二步:b = a ^ b 也就是 b = 6 ^ 5 ^ 5 ,
根据性质一跟性质二可知,b = 6 ^ 5 ^ 5 = 6 ^ 0 = 6
第三步:a = a ^ b 也就是 a = 6 ^ 5 ^ 6 = 6 ^ 6 ^ 5 = 0 ^ 5 = 5

# 存在的问题:
假如 a=6,b=6。此时进行异或操作,会不会根据性质一的N ^ N == 0 ???
注意,不会根据性质一这样的。
因为 a与b虽然值相同,但是他们是两个变量,a与b在计算机中各占一块内存。
假如,a与b指向同一个,那么此时就会出错。

2.一个数组中有一种数出现了奇数次,其他数都出现了偶数次,怎么找到并打印这种数

class xor():
    # 一个数组中有一种数出现了奇数次,其他数都出现了偶数次,怎么找到并打印这种数
    def xor(self, arr):
        n = len(arr)
        eor = 0
        for i in range(n):
            eor ^= arr[i]
        return eor

3.怎样把一个int类型的数,提取出最右侧的1来

假设n
则结果为 n&((~n)+1)

4.一个数组中有两种数出现了奇数次,其他数都出现了偶数次,怎么找到并打印这两种数

推理过程:假设数组中这两种数为a和b,那么我对数组全部进行异或运算,得到的eor=a ^ b,一定如此。又因为a和b是两种数,那么eor=(a ^ b) != 0。那么eor一定存在某一位上不是0而是1。假设eor的第八位为1,那么我们可以将整个数组分为两个部分,即第八位上=0和第八位上=1的,并且a和b 一定是分属于两个部分的。此时,我想只异或第八位上=1的那部分,用eor’表示,那么eor’一定是a或者b,具体是谁不知道,假如是a那么如何去求b呢??那就是eor^eor’。这里第八位为1只是一个例子,那么找哪个呢??就找最右侧为1,根据3来求,知道了最右侧的1,就可以根据推理过程求出问题。

class xor():
    # 一个数组中有两种数出现了奇数次,其他数都出现了偶数次,怎么找到并打印这两种数
    def xor(self, arr):
        n = len(arr)
        eor = 0
        for i in range(n):
            eor ^= arr[i]
        # eor = a ^ b
        # eor != 0
        # eor 必然有一个位置上是1
        rightone = eor & (~eor + 1) # 提取最右侧为1
        onlyone = 0
        for i in range(n):
            if rightone & arr[i] != 0:
                onlyone ^= arr[i]
        otherone = onlyone ^ eor
        return onlyone, otherone

5.输出二进制1的个数

# 1.暴力法,遍历一个一个的数,for
# 2.用异或
class xor():
    # 输出二进制1的个数
    def xor(self, n):
        count = 0
        while n != 0:
            rightone = n & ((~n)+1)  # 每次先提取最右侧的1
            count += 1  # 提取一个计数器加一个
            n ^= rightone  # 提取完就将最右侧的1抹掉
        return count
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值