LeetCode - 166. Fraction to Recurring Decimal
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.
Input: numerator = 1, denominator = 2
Output: “0.5”
Input: numerator = 2, denominator = 1
Output: “2”
Input: numerator = 2, denominator = 3
Output: “0.(6)”
其实就是分数计算成小数形势,如果出现了循环小数,则用 ‘(’ 和 ‘)’ 将循环部分括起来(值得注意的是:因为是从分数转为小数,所以不会出现无限不循环小数,因为能用分数形式表示的都是有理数,而无限不循环小数是无理数,这是因为:分数每次“试商”都要使本次余数小于除数,然而小于除数的余数是有限的,如果除数是17,那么最多有17种余数。所以如果除不尽的话必定产生循环,循环节不会超过17位)。
Solution:
如果不能整除,就不断进行余数补零除以除数。
维护一个映射表map<long long, int> m, 用来记录每个除数对应返回值ret中的位置。
(1)当出现重复的除数n时,说明找到了循环体,根据m[n]找到ret中位置,加上相应的’(‘和’)'将循环体括起来即可返回。
(2)当余数r为0时,返回ret。
注意点:
1、正负号
2、分子为0
3、可能出现INT_MIN/-1的越界情况,因此第一步现将int转为long long
// 小数部分如果余数重复出现两次就表示该小数是循环小数了
string fractionToDecimal(int numerator, int denominator) {
if(denominator == 0) return ""; // 分母为0
if(numerator == 0) return "0"; // 边界条件,分子为0
string res;
// 转为 long long 防止溢出
long long up = numerator, down = denominator;
// 处理正负号
if((up > 0) ^ (down > 0))
res.push_back('-');
// 分子分母全部转换为正数
up = llabs(up);
down = llabs(down);
// 处理整数部分
res += to_string(up / down);
//处理小数部分
up %= down; // 获得余数
if(up == 0) return res; // 余数为0,表示整除了,直接返回结果
res += '.'; // 余数不为0,添加小数点
int idx = res.size() - 1; // 获得小数点的下标
unordered_map<int, int> mp; // map用来记录出现重复数的下标
while(up && mp.count(up) == 0) { // 小数部分:余数不为0且余数还没有出现重复数字
mp[up]= ++idx;
up *= 10; // 余数扩大10倍,然后求商
res += to_string(up / down);
up %= down;
}
if(mp.count(up) == 1) { // 出现循环余数
res.insert(mp[up], "("); // 只能insert字符串
res.push_back(')');
}
return res;
}