在python3中,如何将以负位表示的数字转换为其实际的负int值?
你好,我已经解决了这个leetcode问题。目标是在O(n)时间和0(1)空间中求解该问题。我编写的代码如下:在python3中,如何将以负位表示的数字转换为其实际的负int值?,python,python-3.x,algorithm,bit-manipulation,bit,Python,Python 3.x,Algorithm,Bit Manipulation,Bit,你好,我已经解决了这个leetcode问题。目标是在O(n)时间和0(1)空间中求解该问题。我编写的代码如下: class Solution: def singleNumber(self, nums: List[int]) -> int: counter = [0 for i in range(32)] result = 0 for i in range(32): for num in nums:
class Solution:
def singleNumber(self, nums: List[int]) -> int:
counter = [0 for i in range(32)]
result = 0
for i in range(32):
for num in nums:
if ((num >> i) & 1):
counter[i] += 1
result = result | ((counter[i] % 3) << i)
return self.convert(result)
#return result
def convert(self,x):
if x >= 2**31:
x = (~x & 0xffffffff) + 1
x = -x
return x
我不明白为什么会这样。我需要帮助理解这个减法的工作原理。这正是n位上数字a的2的补码的定义
- 如果数字A为正数,则使用A的二进制代码
- 如果A为负数,则使用2^n+A(或2^n-| A |)的二进制代码。这个数字是必须加在| A |上才能得到2^n的数字(即| A |到2^n的补码,因此这两个补码方法的名称)
关于二的补码还有很多其他的定义(~A+1,~(A-1),等等),但这一个是最有用的,因为它解释了为什么加有符号二的补码数与加正数是完全相同的。该数字在代码中(如果为负数,则添加2^32),如果忽略可能作为执行生成的2^32(并且没有溢出),则添加结果将是正确的。这种算术性质是计算机中使用二的补码的主要原因。这正是n位上数字a的二的补码的定义
- 如果数字A为正数,则使用A的二进制代码
- 如果A为负数,则使用2^n+A(或2^n-| A |)的二进制代码。这个数字是必须加在| A |上才能得到2^n的数字(即| A |到2^n的补码,因此这两个补码方法的名称)
关于二的补码还有很多其他的定义(~A+1,~(A-1),等等),但这一个是最有用的,因为它解释了为什么加有符号二的补码数与加正数是完全相同的。该数字在代码中(如果为负数,则添加2^32),如果忽略可能作为执行生成的2^32(并且没有溢出),则添加结果将是正确的。这个算术性质是计算机中使用二的补码的主要原因。32位有符号整数环绕每一个
2**32
,所以有符号位设置的正数(即=2**31
)具有和负数2**32
更少相同的二进制表示形式。32位带符号整数环绕每个2**32
,所以设置了带符号位的正数(即=2**31
)与负数2**32
less具有相同的二进制表示形式。Python整数是无限大的。当你增加更多的位时,它们不会变成负数,所以二的补码可能不会像预期的那样工作。你可以用不同的方式处理消极情绪
def singleNumber(nums):
result = 0
sign = [1,-1][sum(int(n<0) for n in nums)%3]
for i in range(32):
counter = 0
for num in nums:
counter += (abs(num) >> i) & 1
result = result | ((counter % 3) << i)
return result * sign
while num>0
循环处理数字。它最多运行log(V,3)次,其中V是数字列表中最大的绝对值。因此,它类似于base 2解决方案中i in range(32)循环的,只是它总是使用最小的可能范围。对于任何给定的值模式,while循环的迭代次数将小于或等于一个常数,从而保持主循环的O(n)复杂性
我做了一些性能测试,实际上,当值很小时,base3版本只比base2方法快。base3方法总是执行较少的迭代,但当值较大时,由于模运算和按位运算的开销,它会损失总的执行时间
为了使base2解决方案始终比Base3方法更快,它需要通过反转循环嵌套(位在数字中而不是位中的数字)来优化其迭代:
集合也可以在O(n)中工作:
最后两种解决方案确实使用了与列表大小成比例的可变额外内存量(即不是O(1)空间)。另一方面,它们的运行速度快了30倍,并且支持列表中的任何数据类型。它们还支持迭代器Python整数是无限大的。当你增加更多的位时,它们不会变成负数,所以二的补码可能不会像预期的那样工作。你可以用不同的方式处理消极情绪
def singleNumber(nums):
result = 0
sign = [1,-1][sum(int(n<0) for n in nums)%3]
for i in range(32):
counter = 0
for num in nums:
counter += (abs(num) >> i) & 1
result = result | ((counter % 3) << i)
return result * sign
while num>0
循环处理数字。它最多运行log(V,3)次,其中V是数字列表中最大的绝对值。因此,它类似于base 2解决方案中i in range(32)
循环的,只是它总是使用最小的可能范围。对于任何给定的值模式,while循环的迭代次数将小于或等于一个常数,从而保持主循环的O(n)复杂性
我做了一些性能测试,实际上,当值很小时,base3版本只比base2方法快。base3方法总是执行较少的迭代,但当值较大时,由于模运算和按位运算的开销,它会损失总的执行时间
为了使base2解决方案始终比Base3方法更快,它需要通过反转循环嵌套(位在数字中而不是位中的数字)来优化其迭代:
集合也可以在O(n)中工作:
最后两种解决方案确实使用了与列表大小成比例的可变额外内存量(即不是O(1)空间)。另一方面,它们的运行速度快了30倍,并且支持列表中的任何数据类型。它们还支持迭代器无符号n位数字的最高位的值是2n-1
最高位o的值
def singleNumber(nums):
result = 0
for i in range(32):
counter = sum(1 for n in nums if (n>>i)&1)
if counter > 0: result |= (counter % 3) << i
return result - 2*(result&(1<<31))
result = reduce(lambda r,i:r|sum(1&(n>>i) for n in nums)%3<<i,range(32),sum(n<0 for n in nums)%3*(-1<<32))
def singleNumber(nums):
result = sign = 0
for num in nums:
if num<0 : sign += 1
base3 = 1
num = abs(num)
while num > 0 :
num,rest = divmod(num,3)
rest,base3 = rest*base3, 3*base3
if rest == 0 : continue
digit = result % base3
result = result - digit + (digit+rest)%base3
return result * (1-sign%3*2)
Base10 Base 3 Base 3 digits result (cumulative)
------ ------ ------------- ------
16 121 0 | 1 | 2 | 1 121
16 121 0 | 1 | 2 | 1 212
32 2012 2 | 0 | 1 | 2 2221
16 121 0 | 1 | 2 | 1 2012
-------------
sum of digits % 3 2 | 0 | 1 | 2 ==> 32
def singleNumber(nums):
bits = [0]*len(bin(max(nums,key=abs)))
sign = 0
for num in nums:
if num<0 : sign += 1
num = abs(num)
bit = 0
while num > 0:
if num&1 : bits[bit] += 1
bit += 1
num >>= 1
result = sum(1<<bit for bit,count in enumerate(bits) if count%3)
return result * [1,-1][sign%3]
def singleNumber(nums):
tribits = [0]*len(bin(max(nums,key=abs))) # enough base 2 -> enough 3
sign = 0
for num in nums:
if num<0 : sign += 1
num = abs(num)
base3 = 0
while num > 0:
digit = num%3
if digit: tribits[base3] += digit
base3 += 1
num //= 3
result = sum(count%3 * 3**base3 for base3,count in enumerate(tribits) if count%3)
return result * [1,-1][sign%3]
from collections import Counter
numbers = [1,0,1,0,1,0,99]
singleN = next(n for n,count in Counter(numbers).items() if count == 1)
distinct = set()
multiple = [n for n in numbers if n in distinct or distinct.add(n)]
singleN = min(distinct.difference(multiple))
if n >= 2**31:
n -= 2**32