题目描述
给定两个整数,分别表示分数的分子 numerator 和分母 denominator,以字符串形式返回小数。
如果小数部分为循环小数,则将循环的部分括在括号内。
示例 1:
输入: numerator = 1, denominator = 2 输出: "0.5"
示例 2:
输入: numerator = 2, denominator = 1 输出: "2"
示例 3:
输入: numerator = 2, denominator = 3 输出: "0.(6)"
问题分析
此题先判断结果的符号是不是负的,用变量sig_neg记录。然后将给的被除数和除数转换成long类型的变量,并取绝对值,接下来我们的求解过程使用正数。被除数是numerat,除数是denominat。我们先算一下小数点前的部分,用numerat除以denominat得到商div,得到余数rem。然后我们判断如果余数rem为0那么我们直接返回结果。没有返回说明有小数部分,将ans加上小数点“.”,然后开始计算小数部分。我们创建一个哈希map,用来记录当前余数rem和用此余数计算出的小数点后某位将在ans中记录的位置之间的映射。然后我们创建一个变量point用来记录当前小数点后该记录在某位,初始值是ans.size();也就是小数点后的第一位。然后我们进入while循环,当rem不等于0时,说明还没有除尽,进入循环,我们先判断rem在哈希map中是否已经出现过,如果没有出现过那么我们将rem和当前的point组成映射存入哈希map,然后将point加1;如果rem在哈希map中已经出现过了,说明如果再继续算下去,就会在ans中,从哈希map里存的出现的那个地方开始循环了。所以我们取出哈希map中rem对应的值,就是之前出现过的那个地方,我们在那个地方插入一个左括号,然后在ans尾部加上一个右括号并返回ans。如果并没有返回,说明没有出现循环,我们要用当前的rem算出一个小数位并加到ans的后面。于是先将rem乘以10,然后将rem除以denominat得到的商作为一个小数位存到ans后面,然后我们将rem置为rem除以denominat得到的余数。当不能除尽时,会出现循环小数,所以在while循环里就return了;如果能除尽,那么while循环最终会退出,返回ans即可。注意在所有return时,都要加上正负号的判断。
代码实现
class Solution {
public:
string fractionToDecimal(int numerator, int denominator) {
bool sig_neg = false;
if((numerator > 0 && denominator < 0) || (numerator < 0 && denominator > 0))
sig_neg = true;
long numerat = abs((long)numerator);
long denominat = abs((long)denominator);
string ans;
long div = numerat / denominat;
long rem = numerat % denominat;
if(rem == 0)
return sig_neg? "-" + to_string(div) : to_string(div);
ans = ans + to_string(div) + ".";
int point = ans.size();
unordered_map<long, int> umap;
while(rem != 0){
if(!umap.count(rem)){
umap[rem] = point;
point++;
}
else{
ans.insert(ans.begin() + umap[rem], '(');
ans = ans + ")";
return sig_neg? "-" + ans : ans;
}
rem *= 10;
ans = ans + to_string(rem / denominat);
rem %= denominat;
}
return sig_neg? "-" + ans : ans;
}
};