返回

用有限空间复杂度找出只出现一次的数字 - 剑指 Offer 56(I)

闲谈

1. 问题

给定一个整数数组 nums,其中除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是 O(n),空间复杂度是 O(1)。

例如:

  • 示例 1:
输入:nums = [2,2,1]
输出:[1]
  • 示例 2:
输入:nums = [4,1,2,1,2]
输出:[4]

2. 解决方案

要解决这个问题,我们可以使用以下步骤:

  1. 首先,我们将数组中所有数字进行异或运算。由于异或运算具有交换律和结合律,因此我们可以将所有数字异或在一起得到一个结果。这个结果就是两个只出现一次的数字的异或值。
  2. 然后,我们将这个异或值与 1 进行按位与运算。这样,我们可以得到一个二进制数,其中最高位为 1,而其他位为 0。
  3. 接着,我们将数组中的数字再次进行异或运算,但这一次我们将它们分成两组。第一组是二进制数最高位为 1 的数字,第二组是二进制数最高位为 0 的数字。
  4. 最后,我们将这两组数字分别进行异或运算,就可以得到两个只出现一次的数字。

3. 代码实现

def single_number(nums):
    """
    :type nums: List[int]
    :rtype: List[int]
    """
    # 1. 异或所有数字得到两个只出现一次的数字的异或值
    xor_result = 0
    for num in nums:
        xor_result ^= num

    # 2. 找到最高位为 1 的二进制位
    highest_bit_pos = 0
    while xor_result & (1 << highest_bit_pos) == 0:
        highest_bit_pos += 1

    # 3. 将数组分成两组
    group1 = []
    group2 = []
    for num in nums:
        if num & (1 << highest_bit_pos):
            group1.append(num)
        else:
            group2.append(num)

    # 4. 分别异或两组数字得到两个只出现一次的数字
    single1 = 0
    for num in group1:
        single1 ^= num
    single2 = 0
    for num in group2:
        single2 ^= num

    return [single1, single2]

4. 时间复杂度和空间复杂度分析

  • 时间复杂度:由于我们只需要遍历数组一次,因此时间复杂度为 O(n)。
  • 空间复杂度:由于我们只需要存储两个变量(xor_result 和 highest_bit_pos),因此空间复杂度为 O(1)。

5. 总结

使用有限的空间复杂度找出只出现一次的数字的方法是一种非常有效的算法。这种方法不仅时间复杂度低,而且空间复杂度也低,非常适合解决此类问题。