在问 · 算法题解

166. 分数到小数

题目描述

输入两个整数 numerator(分子)和 denominator(分母)。把这个分数写成小数,以字符串返回。

如果小数部分无限循环,就把循环的那一段放进括号,例如 "0.(6)"。能写成有限小数时,必须返回有限形式;结果是整数时不带小数点。

若有多种正确写法,返回其中任何一种即可。数据保证答案字符串长度小于 10^4。

示例 1
输入:numerator = 1, denominator = 2
输出:"0.5"

解释:1 除以 2 恰好等于 0.5。

示例 2
输入:numerator = 2, denominator = 1
输出:"2"

解释:2 除以 1 是整数 2,不写小数部分。

示例 3
输入:numerator = 4, denominator = 333
输出:"0.(012)"

解释:4/333 = 0.012012…,循环节为 012。

数据范围

  • -2^31 <= numerator, denominator <= 2^31 - 1
  • denominator != 0
  • 答案字符串长度小于 10^4。

解题思路

模拟竖式除法:先写出符号和整数部分,再不断把余数乘 10、写下一位商、取新余数。下一位小数只由当前余数决定,所以一旦某个余数第二次出现,后面的数字就会完全重复。用哈希表记录每个余数第一次出现时对应的结果字符串位置,再次遇到时在那个位置插入左括号,末尾补右括号。余数变成 0 则是有限小数。

为什么正确

seen[r] 是余数 r 第一次出现时 res 的长度,也就是由 r 产生的那一位小数在 res 中的下标。

复杂度分析

时间 O(b),余数最多 b - 1 种;空间 O(b)。

易错点

判断循环要看余数是否重复,不能看商的数字是否重复(例如 1/6 的商 1、6 不同,但循环的是 6)。还要先单独处理符号并取绝对值,其他语言里注意 -2^31 取绝对值会溢出 32 位。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def fractionToDecimal(self, numerator: int, denominator: int) -> str:
        if numerator % denominator == 0:
            return str(numerator // denominator)
        sign = '-' if (numerator < 0) != (denominator < 0) else ''
        a, b = abs(numerator), abs(denominator)
        res = sign + str(a // b) + '.'
        r = a % b
        seen = {}
        while r and r not in seen:
            seen[r] = len(res)
            r *= 10
            res += str(r // b)
            r %= b
        if r:
            res = res[:seen[r]] + '(' + res[seen[r]:] + ')'
        return res

载入编辑器,自己跑一遍 →

字符串 专题的其他题目

查看 字符串 全部题目 →