在python3中,如何将以负位表示的数字转换为其实际的负int值?

在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:

你好,我已经解决了这个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:
                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的补码,因此这两个补码方法的名称)

所以,如果你有一个负数B编码在2的补码中,它的代码中实际上是2^N+B。要得到它的值,你必须从B中减去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的补码,因此这两个补码方法的名称)

所以,如果你有一个负数B编码在2的补码中,它的代码中实际上是2^N+B。要得到它的值,你必须从B中减去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