问题描述
思路分析
这道题的目标是找到数组中只出现了一次的数字,其余的数字均出现了两次。由于题目要求时间复杂度为O(n),并且要求尽量减少额外空间的使用,因此我们可以考虑使用位运算来解决这个问题。
-
异或运算的特性:异或(XOR)运算具有以下几个重要特性:
- 对于任意整数 a,有 a ⊕ a = 0(相同的数字异或会抵消)。
- 对于任意整数 a,有 a ⊕ 0 = a 。
- 异或运算满足交换律和结合律,即顺序无关,a ⊕ b ⊕ c = a ⊕ c ⊕ b 。
-
利用异或找到唯一数字:
- 如果我们将所有的数字依次进行异或运算,那么那些成对出现的数字会互相抵消(异或为 0),最终剩下的就是那个只出现一次的数字。
- 这样我们可以在一次遍历中完成计算,并且不需要额外的存储空间,达到 O(n) 的时间复杂度和 O(1) 的空间复杂度。
算法步骤
- 初始化一个变量
unique_number为 0。 - 遍历数组中的每个元素,并将
unique_number与该元素进行异或运算。 - 遍历结束后,
unique_number中存储的就是只出现一次的数字。
复杂度分析
- 时间复杂度:O(n),因为我们只需要遍历一次数组。
- 空间复杂度:O(1),因为只用了一个额外变量
unique_number。
参考代码
def solution(inp):
unique_number = 0
for number in inp:
unique_number ^= number # 使用异或操作
return unique_number
if __name__ == "__main__":
print(solution([1, 1, 2, 2, 3, 3, 4, 5, 5]) == 4)
print(solution([0, 1, 0, 1, 2]) == 2)
print(solution([7, 3, 3, 7, 10]) == 10)
代码分析
-
初始化
unique_number为 0:unique_number变量用于存储最终结果。初始化为 0 是因为异或的中立元素是 0(也就是 a ⊕ 0 = a )。
-
遍历输入数组
inp:- 代码通过
for number in inp:遍历输入数组inp中的每一个数字number。
- 代码通过
-
异或操作
unique_number ^= number:- 对每个数字
number,都与当前的unique_number进行异或运算。 - 由于数组中除了一个数字其他都成对出现,所以这些成对的数字将互相抵消(每一对会变成 0),最终剩下的
unique_number就是唯一没有成对的数字。
- 对每个数字
-
返回结果:
- 最终
unique_number存储的就是那个唯一出现一次的数字。
- 最终
流程示例
假设输入是 [1, 1, 2, 2, 3, 3, 4, 5, 5]:
- 初始化
unique_number = 0 - 遍历数组并执行异或操作:
0 ^ 1 = 11 ^ 1 = 0(1 和 1 抵消,结果回到 0)0 ^ 2 = 22 ^ 2 = 0(2 和 2 抵消,结果回到 0)0 ^ 3 = 33 ^ 3 = 0(3 和 3 抵消,结果回到 0)0 ^ 4 = 4(4 没有对手,结果是 4)4 ^ 5 = 11 ^ 5 = 4(5 和 5 抵消,最终结果是 4)
最终输出 4,即唯一的数字。