No.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.
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)".
理解题意:
给出一个分数的分子numerator和分母denominator,以string的形式返回该分数
若小数部分为循环的,用括号将其循环部分括起来
分析:
这题其实不会的有点莫名其妙,当时看到题目,有点懵了,这该怎么计算啊,把题目想的过于复杂了。
其实,对于这种题,没有思路或者不会的话,就找个例子,实际做一下,体会一下除法具体的解题步骤,就能找到突破点了。
0.16 6 ) 1.00 0 1 0 - 6 40 - 36 4
实际计算之后,就会发现,当余数出现重复时,小数就开始重复了。
那,怎么知道余数重复了,又怎么知道从哪里开始重复了,就需要记录下来,故要用到哈希表。
而涉及到计算,且INT_MIN转换为正数之后进行除法会使得整数溢出,故,用long long类型
1 #include "stdafx.h" 2 #include <string> 3 #include <iostream> 4 #include <unordered_map> 5 6 using namespace std; 7 8 9 class Solution 10 { 11 public: 12 string fractionToDecimal(int numerator, int denominator) 13 {/* 14 理解题意: 15 给出一个分数的分子numerator和分母denominator,以string的形式返回该分数 16 若小数部分为循环的,用括号将其循环部分括起来 17 实现:参考网上 18 */ 19 if(denominator == 0) 20 return "";//除0问题 21 if(numerator == 0) 22 return "0"; 23 // if(denominator>INT_MAX || denominator<INT_MIN) 24 // return ""; 25 // if(numerator>INT_MAX || numerator<INT_MIN) 26 // return ""; 27 //using long long type make sure there has no integer overflow 28 //有必要转换,因为Min_INT转换为正数时,是会溢出的!!! 29 long long n = numerator; 30 long long d = denominator; 31 32 33 string res(""); 34 //符号问题 35 if((n>0&&d<0) || (n<0&&d>0)) 36 res += "-"; 37 //要转换为整数 38 if(n<0) 39 n = -n; 40 if(d<0) 41 d = -d; 42 //整数部分 43 res += to_string(n/d);//为了转换格式,仅仅+'0'是不行的,比如对于50 44 //此处,有没有必要转换成longlong之后再整除,应该不会溢出吧 45 long long remainder = n%d;//新分子 46 if(remainder == 0) 47 return res; 48 else 49 res += '.'; 50 51 //对应当前余数和当前结果下标!!! 52 //记录的是余数,故若余数再次重复,其对应小数部分也会重复 53 unordered_map<long long, int> rec;//long long是有必要的!!(1/-21474836481) 54 //pos直接以res的尾部开始计数 55 for(int pos = res.size(); remainder != 0; pos++) 56 { 57 if(rec.find(remainder) != rec.end()) 58 {//该余数重复了 59 res.insert(res.begin()+rec[remainder],'(');//!!! 60 res.push_back(')'); 61 return res; 62 } 63 rec[remainder] = pos; 64 res.push_back((remainder*10)/d + '0');//将商插入到结果中!!! 65 //此处可以+'0'的原因是push_back插入的是char型且商只能是一位数 66 remainder = (remainder*10) % d;//余数重新计算 67 } 68 return res; 69 } 70 }; 71 72 73 int main() 74 { 75 Solution sol; 76 // cout<< sol.isNumber(" 46.e3 ")<<endl; 77 /* 78 测试用例:(1, 2);(10, 2);(100, 2);(1, 3);(100, 3);(1, 6);(100, 6);(-1, 4);(1, -3); 79 (-1, -6);(25, 99);(1, 7);(10, 7);(100, 7);(1, 17);(1,1024);( -2147483648, -1999); 80 (-1, -2147483648); 81 */ 82 cout << sol.fractionToDecimal(-21474836481,-1999)<<endl; 83 cout << sol.fractionToDecimal(-1,INT_MIN)<<endl;//溢出 84 85 return 0; 86 }
官方提示:
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).
The key insight here is to notice that once the remainder starts repeating, so does the divided result.
You will need a hash table that maps from the remainder to its position of the fractional part. Once you found a repeating remainder, you may enclose the reoccurring fractional part with parentheses by consulting the position from the table.
The remainder could be zero while doing the division. That means there is no repeating fractional part and you should stop right away.
Just like the question Divide Two Integers, be wary of edge case such as negative fractions and nasty extreme case such as -2147483648 / -1
.
参考:https://github.com/haoel/leetcode/blob/master/algorithms/fractionToRecurringDecimal/fractionToRecurringDecimal.cpp