问题描述:
在一个班级中,每位同学都拿到了一张卡片,上面有一个整数。所有的数字都恰好出现了两次,除了一个数字没有配对。我们需要找到这个唯一没有配对的数字。这个问题要求我们设计一个 时间复杂度为 O(n) 的算法,并且尽量减少额外空间的使用,以提高算法的效率。
约束条件:
- 卡片的数量
n满足1 ≤ n ≤ 1001,即卡片的数量最多为1001。 - 每个卡片上的数字范围是从
0到1000,即0 ≤ cards[i] ≤ 1000。 - 班级人数是奇数,这意味着有且只有一个数字没有配对,其他所有数字都恰好出现两次。
目标:
我们要设计一个 时间复杂度为 O(n) 的算法,尽量减少额外空间的使用,找出唯一不重复的数字。
解题思路
方法 1:利用 异或运算(O(n) 时间复杂度,O(1) 空间复杂度)
异或运算的特性:
异或(XOR)是二进制运算符,其具有以下几个显著的性质:
- 自反性:对于任何数字
a,a ^ a = 0,即同一个数字与自己异或结果为0。 - 结合性与交换性:
a ^ b ^ c = a ^ (b ^ c) = (a ^ b) ^ c,也就是说,异或操作的顺序不影响最终结果。 - 与零的运算:
a ^ 0 = a,即任何数字与0异或结果为该数字本身。
利用异或运算的思想:
通过异或运算,所有出现两次的数字都会相互抵消(因为 a ^ a = 0),最终留下的就是那个没有配对的数字。比如,若数组中有数字 [1, 1, 2, 2, 3],则异或结果为:
复制代码
1 ^ 1 = 0
0 ^ 2 = 2
2 ^ 2 = 0
0 ^ 3 = 3
最终结果是 3
因此,经过一轮遍历,最终的异或结果就是唯一不重复的数字。
代码实现:
python
复制代码
def solution(cards):
unique_number = 0 # 初始化为0
for card in cards:
unique_number ^= card # 对所有卡片上的数字进行异或操作
return unique_number # 最终返回唯一没有配对的数字
# 测试用例
print(solution([1, 1, 2, 2, 3, 3, 4, 5, 5]) == 4) # 输出应为 True
print(solution([0, 1, 0, 1, 2]) == 2) # 输出应为 True
print(solution([7, 3, 3, 7, 10]) == 10) # 输出应为 True
解释:
- 我们从
unique_number = 0开始,将每个卡片上的数字与unique_number进行异或操作。 - 异或的特性使得相同的数字会互相抵消,最后只剩下那个唯一不重复的数字。
复杂度分析:
- 时间复杂度:O(n),其中 n 是卡片的数量。我们只遍历了整个数组一次,每次操作时间为 O(1),因此总的时间复杂度是 O(n)。
- 空间复杂度:O(1),我们只使用了一个额外的变量
unique_number,没有使用额外的存储空间,因此空间复杂度是 O(1)。