Skip to main content

166.分数转化为循环小数

标签: math, hash-table, string

难度: Medium

通过率: 25.65%

原题链接: https://leetcode.com/problems/fraction-to-recurring-decimal/description/

题目描述

给定表示分数的两个整数,分子和分母,返回该分数的字符串格式。``` 如果小数部分是循环的,则将循环部分括在括号中。

如果有多个答案,一律返回其中一种。```

解题思路

我们可以通过长除法来求解这个问题。长除法不仅用于计算小数部分,还能够帮助我们检测到小数部分何时开始循环。具体步骤如下:

  1. 首先处理符号问题,确定结果的符号。若分子和分母中,一者为负数一者为正数,结果就为负数,否则为正。
  2. 通过divmod函数获取商与余数,记录商为整数部分。
  3. 如果余数为零,直接返回结果,因为分数能够被整除,说明没有小数部分。
  4. 否则处理小数部分,创建一个字典用于记录各个余数出现在小数部分的位置。
  5. 启动一个循环,在余数不为0且未出现过的条件下开展:
    • 跟踪余数并更新其所在位置
    • 通过乘以10计算新的商和余数
    • 在结果中记录新的商
  6. 如果余数再次出现,说明出现了循环,在循环位置插入括号并返回结果。
  7. 如果余数为0,表示整数除尽,返回结果。

代码实现

def fraction_to_decimal(numerator: int, denominator: int) -> str:
if numerator == 0:
return "0"

result = []
# If either number is negative (but not both), result is negative
if (numerator < 0) != (denominator < 0):
result.append("-")

# Use absolute values to simplify division
numerator, denominator = abs(numerator), abs(denominator)

# Integer part
integer_part, remainder = divmod(numerator, denominator)
result.append(str(integer_part))

# If no remainder, return the result as is
if remainder == 0:
return "".join(result)

result.append(".")
# Map to store previously seen remainders
remainder_map = {}
remainder_map[remainder] = len(result)

# Calculate fractional part
while remainder != 0:
remainder *= 10
digit, remainder = divmod(remainder, denominator)
result.append(str(digit))

if remainder in remainder_map:
index = remainder_map[remainder]
result.insert(index, "(")
result.append(")")
break

remainder_map[remainder] = len(result)

return "".join(result)

复杂度分析

时间复杂度为 O(n)O(n),其中 nn 为小数部分的长度,因为我们可能会检查小数部分中每个数字。

空间复杂度为 O(1)O(1),不考虑存储结果的空间,余数表的大小理论上受限于 dd