找单独的数|豆包MarsCode AI刷题

46 阅读3分钟

要设计一个时间复杂度为 O(n) 且尽量节省额外空间的算法来找到班级中唯一一个出现一次的数字,我们可以使用位运算的技巧。具体地,我们可以利用 XOR(异或)运算的性质来解决这个问题。

XOR 运算的性质

  1. 交换律:a⊕b=b⊕a
  2. 结合律:(a⊕b)⊕c=a⊕(b⊕c)
  3. 自反性:a⊕a=0
  4. 零的性质:a⊕0=a

由于除了一个数字之外,所有数字都恰好出现了两次,我们可以将所有数字进行异或运算。成对出现的数字会相互抵消(因为 a⊕a=0),最后剩下的就是只出现一次的数字。

算法步骤

  1. 初始化一个变量 result 为 0。
  2. 遍历所有同学手上的数字,对每个数字进行异或运算并更新 result
  3. 遍历结束后,result 就是那个只出现一次的数字。

XOR运算的性质

我们已经提到了一些XOR运算的关键性质,现在让我们更详细地看看它们:

  1. 交换律a ^ b = b ^ a

    • 这意味着XOR运算的顺序不重要。
  2. 结合律(a ^ b) ^ c = a ^ (b ^ c)

    • 这允许我们分组或重新排列XOR运算的顺序。
  3. 自反性a ^ a = 0

    • 任何数与自身进行XOR运算的结果都是0。
  4. 零的性质a ^ 0 = a

    • 任何数与0进行XOR运算的结果都是它本身。
  5. 唯一解:如果 a ^ b = c,那么 a ^ c = b 和 b ^ c = a

    • 这意味着如果我们知道两个数和它们的XOR结果,我们可以找到第三个数。

应用XOR运算找到唯一数字

现在,让我们看看如何使用这些性质来找到那个只出现一次的数字。

假设我们有一个数组 numbers,其中除了一个数字之外,所有数字都恰好出现了两次。

  1. 初始化:我们创建一个变量 result 并将其初始化为0。这个变量将用于存储最终的唯一数字。

  2. 遍历数组:我们遍历数组中的每个数字,并对 result 和当前数字执行XOR运算。

    python复制代码 result = 0

    for number in numbers:
    
        result ^= number
    
  3. 理解XOR过程

    • 当我们遇到成对出现的数字时(比如 a 和 a),result ^ a ^ a 会变成 result ^ 0(因为 a ^ a = 0),最终结果是 result 本身(因为 x ^ 0 = x)。
    • 当我们遇到只出现一次的数字时(比如 b),result ^ b 会将 b 添加到 result 中(因为 x ^ b 就是将 x 的每一位与 b 的相应位进行XOR运算)。
  4. 结束遍历:当我们遍历完整个数组后,result 将包含那个只出现一次的数字,因为所有成对出现的数字都已经相互抵消了。

示例

假设数组是 [2, 3, 2, 3, 1]

  • 初始时,result = 0
  • 遍历到第一个 2result = 0 ^ 2 = 2
  • 遍历到第一个 3result = 2 ^ 3 = 1(二进制:010 ^ 011 = 001)。
  • 遍历到第二个 2result = 1 ^ 2 = 3(二进制:001 ^ 010 = 011)。
  • 遍历到第二个 3result = 3 ^ 3 = 0(二进制:011 ^ 011 = 000)。
  • 遍历到 1result = 0 ^ 1 = 1

最终,result 是 1,这就是那个只出现一次的数字。

总结

通过使用XOR运算,我们能够高效地找到那个只出现一次的数字,而不需要额外的空间(除了一个用于存储结果的变量)。这种方法的时间复杂度是 O(n),其中 n 是数组的长度,非常符合题目的要求。