青训营X豆包MarsCode 技术训练营第五课 | 豆包MarsCode AI 刷题

36 阅读3分钟

第496题 负二进制表示问题

题目分析

题目要求将一个整数 nnn 转换为负二进制(基数为 -2)的形式,并返回其对应的二进制字符串。

在普通的二进制表示中,基数是 2,即每一位上的权值是 2i2^i2i。但是在负二进制表示中,基数是 -2,这意味着每一位上的权值是 (−2)i(-2)^i(−2)i(即交替的正负数)。因此,负二进制的表示方式与普通二进制不同,其在转换过程中有特殊的规则,尤其是在计算余数时,需要进行额外的调整。

解题思路

  • 基本理解

    • 负二进制表示是基数为 -2 的表示法。每一位的权值是 (−2)i(-2)^i(−2)i。
    • 例如,对于 n=2n = 2n=2,其负二进制表示应为 "110",因为 2=(−2)2+(−2)1+(−2)02 = (-2)^2 + (-2)^1 + (-2)^02=(−2)2+(−2)1+(−2)0,即 2=4−2+02 = 4 - 2 + 02=4−2+0。
  • 计算方法

    • 我们使用 除法取余 的方法来转换数字:

      • 每次将数字 nnn 除以 -2,得到商和余数。
      • 余数应始终保持非负(0 或 1),如果余数为负,则需要调整。调整的方法是将余数加 2,同时商增加 1。
    • 重复这个过程,直到商为 0。

    • 最后,将所有余数反向排列,即可得到负二进制表示。

  • 特殊情况

    • 如果 n=0n = 0n=0,直接返回 "0"。

解题代码

def solution(n: int) -> str:
    if n == 0:
        return "0"
    
    result = []
    
    while n != 0:
        n, remainder = divmod(n, -2)
        
        # 处理负余数
        if remainder < 0:
            remainder += 2
            n += 1
        
        result.append(str(remainder))
    
    return ''.join(result[::-1])  # 反转结果并返回

if __name__ == '__main__':
    print(solution(n=2) == '110')
    print(solution(n=3) == '111')
    print(solution(n=0) == '0')

模块解释

  • divmod(n, -2)

    • divmod 是 Python 内置的函数,它返回两个数相除后的商和余数。用它来计算负二进制时,商是 nnn 除以 -2 的商,余数是 nnn 除以 -2 的余数。
    • 在负二进制的情况下,余数的范围应为 0 或 1。如果余数为负,我们通过调整来保证余数非负。
  • 余数调整

    • 如果余数小于 0(即为 -1),我们需要做调整:

      • 将余数加 2 使其变为正数。
      • 同时商增加 1(因为我们修改了余数,商应向上取整)。
  • result.append(str(remainder))

    • 每次计算出余数后,我们将其加入结果列表 result 中,最终得到反向的负二进制表示。
  • ''.join(result[::-1])

    • 由于我们从最低位开始计算余数,结果列表中的余数是从低位到高位排列的,所以需要反转列表来得到正确的负二进制表示。

结论

  • 时间复杂度:O(log|n|),每次操作都会将 nnn 减少一半,因此转换过程的时间复杂度是对数级别的,即与数字的大小的对数成正比。

  • 空间复杂度:O(log|n|),我们需要一个结果列表来存储转换过程中每个余数。由于最多需要进行对数次计算,因此空间复杂度是对数级别的。