Xor 运算

189 阅读2分钟

前言:

异或运算一直是一种神奇的运算。它的运用很广泛,尤其是在密码学的加密技术中,但是同时在其他领域也很发挥着重要的作用。本文诣在介绍异或运算运算性质与一些常见的有趣习题。

有趣的思考

提供一个序列 , 它由 n - 1的数字组成。其中数字 , 属于 1 到 n 且每个数字只出现一次。要求空间不超过4MB , 1<=n<=1071 <= n <= 10^7.

请你找出缺失的那个数字是哪个?

例如:


    输入:
    4
    1 2 3 5
    
    输出:
    4

进入正片

XOR 是什么 ?

异或的英文表示: Exclusive OR ( Exclusive 独家的, 排斥的)

异或运算是一种作用于比特位的运算符 , 它由 ^ 表示。

真值表如下:

xyx ^ y
000
011
101
110

它是作用于每一个比特位上的 , 所以只要任意一个对应的比特位上符合此运算, 那么所有的比特位都符合此运算。

很显然 , 通过观察此真值表 . 我们可以发现异或的运算的运算规则.

运算规则: 比特位相同即是 0 , 不同即是 1

举个非常简单的例子

    x = 011 ----> 3
    y = 101 ----> 5
        x : 0 1 1
        y : 1 0 1
    x ^ y : 1 1 0   -----> 6

XOR 运算性质

性质1 : x ^ 0 = x

观察真值表:

x0x ^ 0
000
100

可以发现 , 其实 x ^ 0 = x , 其中称 0 是 x 的幺元.

性质2 : x ^ x = 0

通过真值表可以证明!

xxx ^ x
000
110

例如:

    x = 101 ----> 5 
        x = 101
        x = 101
    x ^ x = 0

性质3 : 交换律

交换律: xx ^ yy = yy ^ xx

通过真值表可以证明:

xyx ^ yy ^ x
1011
0111
1100
0000

结合 性质1 、 2 、 3 , 我们可以发现一个技巧!

假设我们这样有这样的一段序列 aa ^ bb ^ cc ^ ........ , 那么中间存在的重复出现数对 , 可以直接抵消不会对结果有任何影响

性质4 :结合性

结合性: (x(x ^ y)y) ^ zz = xx ^ (y(y ^ z)z)

意思是: 左边先结合、或者右边先结合其实都是可以的!

注意这里有一个小小的技巧:

xx ^ yy = zz

xx ^ zz = yy

这是也是一个非常重要的性质 , 有的时候可以利用这个性质来优化枚举速度

介绍完性质 , 我们来介绍一些有趣的问题

2、 开始的问题

4MB的空间 , 改变不能通过开数组建映射(压缩成bit位存储也超出), 但是数据要求就是O(n) 必须跑完. 这时候就可以利用性质,将数据全部压缩存储在一个变量中。

形式化表达

ans=ans = A1A_1 ^ A2A_2 ^ A3A_3 ^ A4A_4 ^ A5A_5 ^ ................

因为序列元素的范围是数值范围是 1 到 n , 只有 n - 1 个数 , 且每个数出现一次. 所以我们可以考虑将这个 ansans 异或上 1 - n , n 个数. 这样出现的数就会重复的被计算两次 , 就会抵消.
那么之前出现的数都会被抵消掉 , 只留下那个缺失的数字!

形式化表达

ans=ans = A1A_1 ^ A2A_2 ^ A3A_3 ...... ^ 11 ^ 22 ^ 33 ...... ^ nn

最后ans 就是答案!

2、交换两个数

假设我们需要交换的数 x , y

{x=ˆ yy=ˆ xx=ˆ y\left\{ \begin{aligned} x & \^= \ y & \\ y & \^= \ x \\ x & \^= \ y \end{aligned} \right.

其实这个就比较简单了。 代码就是这样

int a , b;

std::cin >> a >> b;

// 交换两个数

a ^= b;			// a ^ b
b ^= a;			// a ^ b ^ b == a
a ^= b;			// a ^ b ^ a == b

3、唯一的奇数

在一堆偶数出现出现次数的数中找到唯一出现次数为奇数的数

  • 答案非常简单:这堆数异或和 , 原因请读者自己根据性质求证!

4、数集中缺失的两个数

描述:给定一个数集,数字的范围是1-n 且每个数字是只出现一次,请你找到缺失的两个数?

对于这个问题,设我们需要找到的数为 x , y 考虑将数集全部异或上 1 到 n , 那么我们可以得到 x ^ y 因为异或的运算规则,在bit位上相同为 0 , 不同为 1。 那么我们只需要找到,x ^ y bit第一个出现的位置 i。划分成两块 , 每块都存在两个集合。

  • 第一块 i 号位置为 0 (此处就比特位讨论)
    • 数字1 - n 第i号位置为 0 的数
    • 给定的数集的所有的第i号位置为 0 的数
  • 第二块 i 号位置为 1
    • 数字 1 - n 第i号位置为 1 的数
    • 给定的数集的所有的第i号位置为1的数 将第一块的集合1 、2 异或就是其中的一个数 , 将第二块的集合1、2异或就是另外的一个数 答案就这么求出来!