二进制数转字符串

标签: 位运算 数学 字符串

难度: Medium

二进制数转字符串。给定一个介于0和1之间的实数(如0.72),类型为double,打印它的二进制表达式。如果该数字无法精确地用32位以内的二进制表示,则打印“ERROR”。

示例1:

 输入:0.625
 输出:"0.101"

示例2:

 输入:0.1
 输出:"ERROR"
 提示:0.1无法被二进制准确表示

提示:

  • 32位包括输出中的 "0." 这两位。
  • 题目保证输入用例的小数位数最多只有 6

Submission

运行时间: 24 ms

内存: 16.0 MB

class Solution:
    def printBin(self, num: float) -> str:
        left = str(bin(int(num))[2:]) + '.'
        n = int(10**6*(num-int(num)))
        arr = list()
        for mod in [500000, 250000, 125000, 62500, 31250, 15625]:
            arr.append(n//mod)
            n %= mod
        if n > 0:
            return 'ERROR'
        while arr and arr[-1] == 0:
            arr.pop()
        if not arr:
            return left + '0'
        else:
            return left + ''.join(str(x) for x in arr)

Explain

这个题解的思路首先是将输入的浮点数分为整数部分和小数部分。整数部分直接使用Python内置的bin函数转换成二进制,然后将小数部分乘以10的6次方并取整,得到一个较大的整数。这个整数被用于通过一系列的减法操作来确定它的二进制位。题解中设置了一个固定的模数列表,这些模数分别对应二进制小数位的1/2, 1/4, 1/8等的值。算法迭代地检查每个模数能否被当前的数整除,并相应地更新数值。如果在处理完所有模数后,数值不为零,算法返回'ERROR'表示无法精确表示。最后,算法检查尾部的零并去除,生成最终的二进制表示。

时间复杂度: O(1)

空间复杂度: O(1)

class Solution:
    def printBin(self, num: float) -> str:
        # 将整数部分转换为二进制字符串
        left = str(bin(int(num))[2:]) + '.'
        # 将小数部分转换为整数
        n = int(10**6*(num-int(num)))
        arr = list()
        # 处理二进制小数部分的固定模数列表
        for mod in [500000, 250000, 125000, 62500, 31250, 15625]:
            arr.append(n//mod)  # 判断当前模数是否可被整除
            n %= mod  # 更新n为余数
        if n > 0:
            return 'ERROR'  # 如果处理完所有模数后还有剩余,则返回ERROR
        # 移除结果末尾的0
        while arr and arr[-1] == 0:
            arr.pop()
        # 如果结果列表为空,则只有整数部分,返回'0'作为小数部分
        if not arr:
            return left + '0'
        else:
            return left + ''.join(str(x) for x in arr)  # 将结果列表转换为字符串并返回

Explore

选择将小数部分乘以10的6次方是为了尽可能地提高转换过程中的精确度,同时也保证处理过程在计算机中的实用性。10的6次方(即1000000)能够确保大部分需要精确到六位小数的数都可以在不产生过多溢出的情况下被处理。这个数值足够大,可以在不失去太多精度的情况下将小数部分转换为一个较大的整数,便于后续的二进制转换。如果选择更小的数,比如10的3次方或更小,可能无法捕捉到足够的小数精度;而选择更大的数虽然可以增加精度,但可能会导致在某些环境下处理大数时的性能问题。

这些模数值是基于二进制小数位的权重确定的。在二进制系统中,每一位小数对应的权重是2的递减幂次。例如,第一位小数位对应1/2,第二位对应1/4,第三位对应1/8,以此类推。将小数乘以10的6次方后,这些权重可以转换为整数模数。500000代表1/2,250000代表1/4,125000代表1/8等。这样的设计确保了每个小数位对应的二进制位可以通过整除和取余操作来确定,是与特定的二进制位精度直接相关的。

当处理完所有模数后,如果数值不为零,这意味着小数部分不能被完全表示为二进制小数的有限序列。在二进制表示中,只能精确表示那些小数部分为2的负整数幂次之和的数。如果在限定的模数处理后仍有剩余的数值,这表明原始数无法通过简单的2的幂次分解来完全表示。由于题目限制了32位的输出长度,包括'0.'在内,如果不能在这个长度内完全表示小数部分,就必须返回'ERROR'。这种判断逻辑保证了二进制表示的精确性和实用性。