在一个班级中,每位同学都拿到了一张卡片,上面有一个整数。有趣的是,除了一个数字之外,所有的数字都恰好出现了两次。现在需要你帮助班长小C快速找到那个拿了独特数字卡片的同学手上的数字是什么。 找单独的数 - MarsCode
题目要求:
- 设计一个算法,使其时间复杂度为
O(n)
,其中n
是班级的人数。 - 尽量减少额外空间的使用,以体现你的算法优化能力。
本题目的算法标签类别为位运算,可通过异或运算符可求解出答案。
异或运算符
异或运算符(XOR)具有一些独特的性质,使得它在某些情况下能够用于解决特定的问题,比如在一组数组中找到只出现一次的数字(而其它数字都出现了两次)。以下是异或运算符能够实现这一功能的原因:
- 自反性:
异或运算满足 a⊕a=0。这意味着任何数与自身进行异或运算的结果都是0。 - 零的恒等性:
异或运算满足 a⊕0=a。这意味着任何数与0进行异或运算的结果仍然是它本身。 - 交换律和结合律:
异或运算满足交换律 a⊕b=b⊕a 和结合律 a⊕(b⊕c)=(a⊕b)⊕c。这意味着异或运算的顺序不重要,并且可以进行分组计算。
利用这些性质,我们可以对一组数组中的数字进行异或运算来找到只出现一次的数字。假设数组中有 n 个数字,其中 n−1 个数字都出现了两次,只有一个数字出现了一次。我们按以下步骤进行:
-
初始化结果变量:
设一个变量result
,初始化为0。 -
遍历数组:
遍历数组中的每一个元素,将result
与当前元素进行异或运算。result = 0 for num in array: result = result ^ num
-
得到结果:
由于所有成对出现的数字在异或运算后会抵消为0,而只出现一次的数字与0异或后仍然是它本身,所以最终result
就是那个只出现一次的数字。
举个例子,假设数组是 [4, 1, 2, 1, 2]
,其中 4
只出现了一次:
- 初始
result = 0
- 第一个元素
4
,result = 0 ^ 4 = 4
- 第二个元素
1
,result = 4 ^ 1 = 5
- 第三个元素
2
,result = 5 ^ 2 = 7
- 第四个元素
1
,result = 7 ^ 1 = 6
(因为1
之前已经出现过一次,所以1 ^ 1 = 0
,相当于抵消) - 第五个元素
2
,result = 6 ^ 2 = 4
(因为2
之前已经出现过一次,所以2 ^ 2 = 0
,相当于抵消)
最终 result
的值是 4
,这就是数组中只出现一次的数字。
时间复杂度为 O(n),空间复杂度为 O(1),非常高效。