找单独的数(位运算实现和哈希实现)

前言

在众多类中,如何寻找出那个与众不同的类


问题:

给n个数,不重复的共有m+1个数,其中的m个数重复了x次,一个数重复了y次,即 \(n = m*x + 1*y\),找到这个y,总结各种O(n)时间实现的算法, 异或(x为2,y为1),位运算,哈希表,等等

在给定的条件下,我们需要找到一个数组中唯一出现 y 次的那个数字,而其他数字都出现了 x 次。为了满足 O(n) 的时间复杂度要求,我们可以使用多种方法来解决这个问题。以下是一些常见的算法和它们的实现细节:

1. 异或运算(仅适用于 x = 2, y = 1)

x = 2y = 1 时,可以使用异或运算来解决问题。因为任何数与自身异或结果为0,任何数与0异或结果为其本身。

实现代码

def singleNumber(nums):
    result = 0
    for num in nums:
        result ^= num
    return result

# 测试样例
print(singleNumber([1, 1, 2, 2, 3]))  # 输出3

2. 位运算(适用于任意 x 和 y)

对于更一般的情况,可以使用位运算来统计每一位上的1的数量,并对 x 取模来找出那个唯一的数字。

实现代码

def singleNumber(nums, x, y):
    bit_count = [0] * 32  # 假设整数是32位

    # 统计每一位上1的数量
    for num in nums:
        for i in range(32):
            if (num >> i) & 1:
                bit_count[i] += 1

    # 根据bit_count数组重建结果数字
    result = 0
    for i in range(32):
        if bit_count[i] % x != bit_count[i] % y:
            if i == 31:  # 符号位处理
                result -= (1 << 31)
            else:
                result |= (1 << i)

    return result

# 测试样例
print(singleNumber([1, 1, 1, 2, 2, 2, 3, 3, 3, 4], 3, 1))  # 输出4
print(singleNumber([0, 0, 0, 1, 1, 1, 2], 3, 1))  # 输出2
print(singleNumber([7, 7, 7, 3, 3, 3, 10], 3, 1))  # 输出10

3. 哈希表

在 Python 中,字典(dict)和集合(set)都是基于哈希表实现的。

  • 字典 (dict)
    哈希表实现:Python 的字典是一种无序的键值对集合,其中每个键都必须是可哈希的(即不可变且实现了__hash__()方法和__eq__()方法)。键通过其哈希值被快速映射到特定的存储位置,这使得查找、插入和删除操作在平均情况下都能达到常数时间复杂度O(1)。
    特点:键唯一性。如果尝试添加一个已经存在的键,则新值会替换旧值。

  • 集合 (set)
    哈希表实现:类似字典,集合也是一种无序的不重复元素序列。由于也是基于哈希表实现,因此它支持快速的成员检查、添加和移除操作,这些操作通常也具有平均时间复杂度O(1)。
    特点:元素唯一性。试图向集合中添加重复元素将不会产生任何效果。

哈希表方法通过记录每个数字的出现次数来找到那个唯一的数字。这种方法的时间复杂度是 O(n),但空间复杂度也是 O(n)。

字典

实现代码

from collections import Counter

def singleNumber(nums, x, y):
    count_dict = Counter(nums)

    # 找到出现次数为y的数字
    for num, count in count_dict.items():
        if count == y:
            return num

# 测试样例
print(singleNumber([1, 1, 1, 2, 2, 2, 3, 3, 3, 4], 3, 1))  # 输出4
print(singleNumber([0, 0, 0, 1, 1, 1, 2], 3, 1))  # 输出2
print(singleNumber([7, 7, 7, 3, 3, 3, 10], 3, 1))  # 输出10

对于x=2,y=1

def hash_unique(nums:List[int])->int:
    hash_dicts = {}
    for i in nums:
        if i in hash_dicts:
            hash_dicts[i]+=1
        else:
            hash_dicts[i] = 1
    for k,v in hash_dicts.items():
        if v == 1:
            print(k)
            return k

集合

集合方法可以通过求和的方式来计算唯一的数字。假设所有数字的范围已知,可以通过求和的方式简化问题。

实现代码

def singleNumber(nums, x, y):
    unique_sum = sum(set(nums))
    total_sum = sum(nums)
    # 计算公式:unique_num = (unique_sum * x - total_sum) / (x - y)
    unique_num = (unique_sum * x - total_sum) // (x - y)
    return unique_num

# 测试样例
print(singleNumber([1, 1, 1, 2, 2, 2, 3, 3, 3, 4], 3, 1))  # 输出4
print(singleNumber([0, 0, 0, 1, 1, 1, 2], 3, 1))  # 输出2
print(singleNumber([7, 7, 7, 3, 3, 3, 10], 3, 1))  # 输出10

注意:这种方法适用于所有数字都在一个已知范围内,并且这个范围内的所有数字都可以被枚举的情况。如果数字范围过大或者不可枚举,则不适合使用这种方法。

总结

  1. 异或运算:适用于 x = 2 且 y = 1 的情况,简单高效。
  2. 位运算:适用于任意 x 和 y,通过统计每一位上的1的数量并取模来找到唯一的数字。
  3. 哈希表:适用于任意 x 和 y,通过记录每个数字的出现次数来找到唯一的数字,但空间复杂度较高。
  4. 集合:适用于数字范围已知的情况,通过求和的方式来计算唯一的数字。
posted @ 2025-03-12 13:29  玉米面手雷王  阅读(40)  评论(0)    收藏  举报