如何解决Python按位异或运算从列表中查找唯一数字 您的问题的解决方案基于此概念
我被要求从 Python 中的数字列表中找出仅在列表中出现一次的数字。像往常一样,我可以使用立即出现的正常方法轻松解决它:
class Solution(object):
def singleNumber(self,nums):
"""
:type nums: List[int]
:rtype: int
"""
for i in nums:
if(nums.count(i) == 1):
return i
return nums[0]
试图找到另一种更好的方法,互联网建议我使用按位异或运算,并提供了以下代码,它更快更有效。代码如下:
class Solution(object):
def singleNumber(self,nums):
"""
:type nums: List[int]
:rtype: int
"""
a = 0
for i in nums:
a^=i
print(a)
return a
逻辑是,如果我们对 2 个相同的位(0,0 或 1,1)进行 XOR 运算,答案将始终为 0,如果位不同,则为 1。使用这个,它提出了这样的方法。
我的思绪陷入困境,试图意识到 XOR 操作的正常概念在这里会有什么用处!我理解他们所说的相同和不同位的逻辑,但是通过他们的代码,每次我对下一位执行 XOR 时,都会弹出一个新数字,那么我们如何保证只有出现一次的数字才会进化?
我觉得无能为力。发布代码片段然后要求解释可能不是一个好方法,但我觉得这个解决方案非常有趣,我很想知道按位 XOR 是如何提供帮助的!如果有人有想法,请帮助!提前致谢。
注意:在列表中,除了一个之外,所有数字都出现了两次。
解决方法
这个 XOR 解决方案的一般限制有点不同:
您有一个列表,其中恰好一个数字出现奇数次,所有其他数字出现偶数次,需要找到奇数个。
如果位相同,则 XOR 翻转位:
b1 XOR b1 > b0
b0 XOR b0 > b0
b1 XOR b0 > b1
b0 XOR b1 > b1
您有一个任意的起始值(列表中的第一个数字),例如:
01010111011111101
如果所有其他数字出现偶数次,您至少会看到每个位模式两次。
第一次你有一对位和
- 每 0,1 位翻转为 1
- 每 1,0 位翻转为 1
- 每 1,1 位翻转为 0
然后您再次遇到相同的数字(因为数字中出现偶数次):
- 上次翻转后有 1 位,再次遇到 1 位,因此翻转为 0
- 上次翻转后得到 1 位,再次遇到 0 位,因此您保持在 1
- 上次翻转后得到 0 位,再次遇到 1 位,因此翻转为 1
您现在又回到了原来的数字,因为偶数出现的数字会相互抵消:
101010010
xor 101010010
-------------
000000000
如果你将任何其他数字与 000000000 进行异或,你就会得到另一个数字。
,我认为不了解异或运算的特性,很难理解代码的作用
这是异或运算的特性
如果位相同,则结果为 0。如果位不同,则结果为 1。
下表将清楚地说明上述 XOR 属性。
+---+---+---------+
| a | b | a XOR b |
+---+---+---------+
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
+---+---+---------+
您的问题的解决方案基于此概念。
异或的一个有趣的特性是
- 当你对同一个数字进行异或运算时,你会得到零次
- 当你对同一个数字进行奇数次异或运算时,你会得到这个数字本身
例如 - 数字 2(二进制中的 2 是 - 0010)
让我们
-
执行 2 (偶数次)的异或运算
0010 0010 ---- 0000 <- XOR (Value is 0)
-
执行 2 (奇数次)的异或运算
0010 0010 0010 ---- 0010 <- XOR (Value is 2)
无论出现偶数次的任何数字最终都会导致零并且零与出现奇数次的数字进行异或将给你相同的数字(出现奇数次)
而将 a
初始化为 0
的原因是 - 0
XOR x
会给 x
本身
说 x = 3
0 -> 0000
3 -> 0011
----
0011 <- XOR (Value is 3)
编辑 - 基于 OP 的怀疑
对于输入 arr = [1,2,4,1]
你问为什么你得到任意值 - 1,3,1,5,4
它们不是任意的。它们是 a
和 i
之间异或运算的结果。
a
的初始值 = 0
- 第一次迭代:i = 1(0001); a = 0 (0000)
i: 0000 a: 0001 ---- 0001 -> Decimal value is 1 stored in a
- 第二次迭代:i = 2(0010); a = 1 (0001)
i: 0010 a: 0001 ---- 0011 -> Decimal value is 3 stored in a
- 第三次迭代:i = 2(0010); a = 3 (0011)
i: 0010 a: 0011 ---- 0001 -> Decimal value is 1 stored in a
- 第四次迭代:i = 4(0100); a = 1 (0001)
i: 0100 a: 0001 ---- 0101 -> Decimal value is 5 stored in a
- 第五次迭代:i = 1(0001); a = 5 (0101)
i: 0001 a: 0101 ---- 0100 -> Decimal value is 4 stored in a
异或运算的相关属性有:
- 是associative,所以
(a ^ b) ^ c == a ^ (b ^ c)
- 是commutative,所以
a ^ b == b ^ a
- 它有
0
作为 identity element,所以a ^ 0 == 0 ^ a == a
- 每个元素都是它自己的 inverse,所以
a ^ a == 0
所以考虑一下当您的输入列表类似于 [3,3]
时会发生什么。从前两个属性,我们有 (((3 ^ 4) ^ 5) ^ 4) ^ 3
与 (3 ^ 3) ^ (4 ^ 4) ^ 5
相同,从第四个属性这与 0 ^ 0 ^ 5
相同,从第三个属性得到结果是 {{1 }}。实际上,每个出现偶数次的元素都会与自身抵消,只留下出现一次(或奇数次)的元素。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。