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.
For example,
- Given numerator = 1, denominator = 2, return "0.5".
- Given numerator = 2, denominator = 1, return "2".
- Given numerator = 2, denominator = 3, return "0.(6)".
这道题是分数转换为小数,题目难度为Medium。
要将分数转换为小数,可以从小数的计算过程着手。以1/8为例,分为以下几步:
-
商为0,余数为1,记录当前的商,开始进入小数部分,至此小数为“0.”
-
拿余数1乘10作为新的分子继续计算,商为1,余数为2,至此小数为“0.1”
-
拿余数2乘10作为新的分子继续计算,商为2,余数为4,至此小数为“0.12”
-
拿余数4乘10作为新的分子继续计算,商为5,余数为0,计算结束,最终小数为“0.125”
题目的关键部分在于判断分数是否是无限循环小数,如果计算过程中当前余数和之前的余数相同,说明小数开始循环,就可以结束计算了。要判断余数是否重复出现过,自然会想到用Hash Table。另外题目还需要注意两点:分子和分母有可能是负数,如果符号不同结果中要有负号;分数是无限循环小数时要在结果中加入括号,因此需要在Hash Table中记录下余数出现的位置,重复出现时在该位置之前插入左括号。运算结束的条件是余数为0或者余数出现重复。具体代码:
class Solution {
public:
string fractionToDecimal(int numerator, int denominator) {
string rst;
unordered_map<long long, int> hash;
int pos;
long long quotient, remainder, curNum, curDen;
if((numerator < 0 && denominator > 0) || (numerator > 0 && denominator < 0)) rst += "-";
if(numerator < 0) curNum = abs((long long)numerator);
else curNum = numerator;
if(denominator < 0) curDen = abs((long long)denominator);
else curDen = denominator;
quotient = curNum / curDen;
remainder = curNum % curDen;
rst += to_string(quotient);
if(remainder) rst += ".";
pos = rst.size();
hash[remainder] = pos;
while(remainder) {
curNum = remainder * 10;
remainder = curNum % curDen;
quotient = curNum / curDen;
rst += to_string(quotient);
if(remainder == 0) {
break;
}
else {
auto it = hash.find(remainder);
if(it != hash.end()) {
rst.insert(it->second, "(");
rst += ")";
break;
}
else {
pos++;
hash[remainder] = pos;
}
}
}
return rst;
}
};