问题
Given two integers representing the numerator and denominator of a fraction, return the fraction in string format.
If the fractional part is repeating, enclose the repeating part in parentheses.
例子
- Given numerator = 1, denominator = 2, return "0.5".
- Given numerator = 2, denominator = 1, return "2".
- Given numerator = 2, denominator = 3, return "0.(6)".
分析
模拟除法的运算过程。设numerator = 10, denominator = 6.
- numerator = 10, denominator = 6, quotient = 1, remander = 4, res = "1.";
- numerator = remander * 10 = 40, denominator = 6, quotient = 6, remander = 4, res = "1.6";
- numerator = remander * 10 = 40, denominator = 6, quotient = 6, remander = 4, res = "1.66".
到第三步可以发现,以后每一步remander都是4,quotient都是6,即开始循环。res应该为"1.(6)".
所以我们要模拟上面的运算,直到remander开始重复某一数字,设该数字为R。用一个map来保存remander和它出现的位置。在remander第一次出现R的位置插入'(',在最后的位置插入')'。
除此之外,还有考虑一下几点:
- numerator和denominator异号时,在res前加'-';
- quotient和remander要定义成long long,防止溢出,例如numerator = -2147483648, denominator = -1;
- 求int的绝对值时,有溢出的风险,需要先把int转换成long long.
要点
- 理解小数循环节的含义,能够模拟除法运算:不断用余数乘10除以除数,直到余数为0。当余数开始出现重复数字时,商的小数开始循环;
- 注意数值类型的溢出问题;
- string关于char的构造函数为string(size_t n, char c).
时间复杂度
O(n), n位数字的长度
空间复杂度
O(n)
代码
class Solution {
public:
string fractionToDecimal(int numerator, int denominator) {
if (numerator == 0) return "0";
string res;
if (numerator < 0 ^ denominator < 0)
res += '-';
long long numer = abs((long long)numerator);
long long denom = abs((long long)denominator);
long long quotient = numer / denom;
long long remander = numer % denom;
res += to_string(quotient);
if (remander == 0) return res;
res += '.';
unordered_map<long long, int> map;
while (remander) {
quotient = remander * 10 / denom;
if (map.find(remander) != map.end()) {
res.insert(map[remander], 1, '(');
res += ')';
break;
}
map[remander] = res.size();
res += to_string(quotient);
remander = remander * 10 % denom;
}
return res;
}
};