题目难度: 中等

原题链接

今天继续更新程序员面试金典系列, 大家在公众号 算法精选 里回复 面试金典 就能看到该系列当前连载的所有文章了, 记得关注哦~

题目描述

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

示例 1:

  • 输入:0.625
  • 输出:"0.101"

示例 2:

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

提示:

32 位包括输出中的"0."这两位。

题目思考

  1. 二进制小数有哪些性质?

解决方案

思路

  • 相信大家都比较熟悉二进制整数, 其实二进制小数也是采用类似的表示方法
  • 举个例子, 二进制 0.101 就相当于2^(-1) + 2^(-3) = 0.5 + 0.125 = 0.625 (注意这里的^是求幂符号)
  • 那如何从十进制小数反推出二进制呢?
  • 根据上面的式子, 小数点后的第一位对应的是 2^(-1), 乘以 一次 2 就得到 1; 而第三位对应的是 2^(-3), 乘以 三次 2 就得到 1
  • 所以我们可以对当前的十进制小数不断乘以 2, 如果得到的结果大于等于 1, 就说明当前这个二进制位是 1, 反之则是 0
  • 另外如果得到的数大于等于 1 的话, 还要减去整数部分, 只保留小数部分, 这样就不会对后面的计算产生影响 (否则后面的所有数都大于等于 1 了)
  • 最后如果数字变成 0, 就说明成功得到了对应的二进制小数; 如果超出 32 位表示范围, 则返回错误
  • 另外注意浮点数都存在精度误差, 所以这里只要当前小数的绝对值小于等于一个极小数就认为它是 0

复杂度

  • 时间复杂度 O(1): 最多只需要循环 32 次
  • 空间复杂度 O(1): 只使用了几个常数空间的变量

代码

class Solution:
    def printBin(self, num: float) -> str:
        # 利用二进制小数的性质
        # 每次*2, 然后把整数位加到结果中, 小数位继续运算, 直到小数变成0或者超过32位范围
        # 注意浮点数有精度误差, 只要其绝对值小于等于一个极小数就认为它是0
        res = '0.'
        epsilon = 1e-9
        while len(res) < 32 and abs(num) > epsilon:
            num *= 2
            if num >= 1:
                # 当前位是1, 继续计算小数位
                res += '1'
                num -= 1
            else:
                # 当前位是0
                res += '0'
        if len(res) >= 32:
            # 超出了32位范围, 返回错误
            return 'ERROR'
        return res

大家可以在下面这些地方找到我~😊

我的 GitHub

我的 Leetcode

我的 CSDN

我的知乎专栏

我的头条号

我的牛客网博客

我的公众号: 算法精选, 欢迎大家扫码关注~😊

算法精选 - 微信扫一扫关注我