在一个班级集体里,每位同学均领取到了一张卡片,卡片上标记着一个整数。颇为有趣的是,除了某一个特定数字仅出现一次之外,其余的数字都恰好出现了两次。此刻,班长小 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 与当前元素进行异或运算。
以下是对应的 Python 代码解读:
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),效率颇高。