前言
在众多类中,如何寻找出那个与众不同的类
问题:
给n个数,不重复的共有m+1个数,其中的m个数重复了x次,一个数重复了y次,即 $n = mx + 1y$,找到这个y,总结各种O(n)时间实现的算法, 异或(x为2,y为1),位运算,哈希表,等等
在给定的条件下,我们需要找到一个数组中唯一出现 y
次的那个数字,而其他数字都出现了 x
次。为了满足 O(n) 的时间复杂度要求,我们可以使用多种方法来解决这个问题。以下是一些常见的算法和它们的实现细节:
1. 异或运算(仅适用于 x = 2, y = 1)
当 x = 2
且 y = 1
时,可以使用异或运算来解决问题。因为任何数与自身异或结果为0,任何数与0异或结果为其本身。
实现代码
def singleNumber(nums):result = 0for num in nums:result ^= numreturn 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 = 0for 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 Counterdef 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]+=1else:hash_dicts[i] = 1for 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
注意:这种方法适用于所有数字都在一个已知范围内,并且这个范围内的所有数字都可以被枚举的情况。如果数字范围过大或者不可枚举,则不适合使用这种方法。
总结
- 异或运算:适用于
x = 2
且y = 1
的情况,简单高效。 - 位运算:适用于任意
x
和y
,通过统计每一位上的1的数量并取模来找到唯一的数字。 - 哈希表:适用于任意
x
和y
,通过记录每个数字的出现次数来找到唯一的数字,但空间复杂度较高。 - 集合:适用于数字范围已知的情况,通过求和的方式来计算唯一的数字。