题目:
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,
题意:给定一个分子和一个分母,以字符串的形式返回该小数。如果小数无限循环的话,用括号扩住循环体。
思路:手写计算除法方法
0.16
6 ) 1.00
0
1 0 <-- Remainder=1, mark 1 as seen at position=0.
- 6
40 <-- Remainder=4, mark 4 as seen at position=1.
- 36
4 <-- Remainder=4 was seen before at position=1, so the fractional part which is 16 starts repeating at position=1 => 1(6).
关键点就是如何确定循环体?
我们用一个hashmap记录每一个余数,以及该余数出现的位置,当出现重复的余数时,说明除法开始进入循环,两个重复余数之间的部分就是循环体。
示例:1/13=0.076923076923076923...,当小数部分第二次出现0时,就意味着开始了循环,那么需要把076923用括号括起来,结果为0.(076923)。
Attention:
1. HashMap的构造
HashMap<key, value>分别对应<当前余数,对应的结果下标(位置)>。这样可以根据key即余数来判断是否进入循环;并且这样之后才能在循环体的第一个数前插入‘(’;这种利用map的方法十分巧妙。既标记了余数,又标记了位置。
2. 考虑正负数,和溢出
考虑结果的正负数,我们先判断符号,然后都转为正数运算。
考虑溢出,如果输入为INT.MIN_VALUE, 取绝对值后会溢出,所以我们需要调整计算的分子分母和余数的类型为long 或 long long.
<span style="font-size:14px;"> //(2)得到绝对值 //int n = abs(numerator); //int d = abs(denominator); long long int n = numerator, d = denominator; n=abs(n); d=abs(d); //(3) 计算整数部分 ret += to_string(n/d); long long int r= n % d; //余数r </span>
溢出结果 将变成负数的除法
30 / 35 test cases passed.
|
Status: Wrong Answer |
Submitted:
32 minutes ago
|
Input: | -1, -2147483648 |
Output: | "0.000000000-4-6-5-6-6-1-2-8-7-30-7-7-3-9-2-5-7-8-1-2-5" |
Expected: | "0.0000000004656612873077392578125" |
3. 先处理特殊情况,分子或分母为0
<span style="font-size:14px;"> //计算特殊情况,分子/分母为0 if(numerator == 0) return "0"; if(denominator == 0) return "";</span>4. 注意我们计算除法的步骤:
(1)先判断符号 (2)计算整数部分,是否有余数,有,加小数点'.',继续计算;无,返回结果 (3)余数补零,和分母作除法,计入结果(r *= 10, ret += to_string(r / d))(4) 如果还有余数,将余数作为下一次计算的分子(r %= d)直到出现循环或者没有余数,结束计算。
5. string的insert函数
string& insert (size_t pos, size_t n, char c);
复杂度:O(1) 空间复杂度O(1) 都是常数。可以表示为分数,说明一定是有理数。
AC Code:
<span style="font-size:14px;">class Solution { public: string fractionToDecimal(int numerator, int denominator) { //计算特殊情况,分子/分母为0 if(numerator == 0) return "0"; if(denominator == 0) return ""; string ret; //(1)判断符号位 if(numerator < 0 ^ denominator < 0) ret += '-'; //(2)得到绝对值 //int n = abs(numerator); //int d = abs(denominator); long long int n = numerator, d = denominator; n=abs(n); d=abs(d); //(3) 计算整数部分 ret += to_string(n/d); long long int r= n % d; //余数r if(r == 0) return ret; ret += '.'; //(4) 计算小数部分 unordered_map<int, int> pmap; //记录位置信息 余数的位置 while(r) { //如果这个余数出现过,说明分数除法开始循环 停止计算,在第一次出现的位置插入‘(’,在最后插入‘)’ if(pmap.count(r) == 1) { ret.insert(pmap[r], 1,'('); ret += ')'; return ret; } //记录此时的余数和位置 pmap[r] = ret.size(); //如果没有出现循环,按照手写计算除法的方法计算除法: 补零,做除法;然后取余数,作为下一次计算分子 r *= 10; ret += to_string(r / d); r %= d; } return ret; } };</span>