剑指 Offer 56 - I. 数组中数字出现的次数

204 阅读2分钟

题目描述

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

示例 1:
输入:nums = [4,1,4,6]
输出:[1,6] 或 [6,1]

示例 2:
输入:nums = [1,2,10,4,1,4,3,3]
输出:[2,10] 或 [10,2]

解题思路1: Map法

遍历数组, 将把元素作为key, 元素出现的次数作为val构造map. 然后在遍历map, 那个元素出现了一次并返回

示例代码:

def singleNumber2(self, nums: List[int]) -> int:
    map = {}
    for n in nums:
        if n not in map:
            map[n] = 1
        else:
            map[n] = map[n] + 1
    for key, val in map.items():
        if val == 1:
            return key

    return 0

解题思路2: 位运算法, 来自K神题解

  1. 在前边的题目中, 我们使用位运算解答过, "出了一个元素出现一次外, 其他元素都出现2次"的题目. 2.
  2. 使用^运算, 所有出现2次的元素都会被置为0, 只留下出现一次的元素. 但这个题目中有2个元素出现一次(假设为n, m), 将所有元素^后, 得到的结果是 X = n^m
  3. 此时,如果我们能够将原数组根据X分为2部分, A = (x1, x1, y1, y1, n) 和 B = (z1, z1, h1, h1, m), 那么, A ^ X 就得到 n, B ^ X 就得到 m
  4. 那么如何分组呢? 类比我们区分奇偶数用 1 & num == 0 来区分, 所以我们可以用 X & num == 0来将原数组分为2组

示例代码:

def singleNumbers(self, nums: List[int]) -> List[int]:
    x, y, n, m = 0, 0, 0, 1
    for num in nums: # 步骤2. 将所有元素先进行^, 得到 n^m
        n ^= num

    while n & m == 0: # 步骤4. 通过 << 计算出合适的 m
        m <<= 1

    for num in nums: # 步骤3. 使用步骤4得到的m, 将数组分组并^得到 x,y
        if num & m:
            x ^= num
        else:
            y ^= num
    return x, y