博文中会简要介绍Leetcode P0166题目分析及解题思路。
“Fraction to Recurring Decimal”是一道考验耐心和细心的题目,同时也考察数学功底。由于题目中要求如果存在循环小数,则只需要用小括号将一个循环节包裹起来即可,所以我们需要找到循环节或者是代表出现循环节的特征。这里会运用到HashTable来帮助我们找到循环节。
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.
If multiple answers are possible, return any of them.
核心思路是运用数学上的特征。如果一个数除以另一个数的余数在不断循环,那么其商也会出现循环节。所以我们只需要用一个HashTable记录每一个余数对应的小数结果,一旦出现相同的余数则可以知道出现了循环节,此时就可以退出循环。
为了避免过多的字符串拼接操作,我们可以用一个整型数组或者链表存储每个小数位上出现的余数。由于我们用HashTable记录了每个余数对应的小数结果,我们可以通过遍历这个数组得到每个小数位上应该出现的小数结果。
以下是Java的题解代码实现。
class Solution {
public String fractionToDecimal(int numerator, int denominator) {
if (numerator == 0)
return "0";
StringBuilder decimal = new StringBuilder();
// Set the sign
if ((numerator > 0 && denominator < 0)
|| (numerator < 0 && denominator > 0)) {
decimal.append("-");
}
// Avoid overflow
long longn = Math.abs((long) numerator);
long longd = Math.abs((long) denominator);
// Calculate the integer part first
if (longn < longd) {
decimal.append("0.");
}
else {
decimal.append(longn/longd);
longn = longn%longd;
if (longn == 0)
return decimal.toString();
else
decimal.append(".");
}
long remainder = longn;
Map<Long, Long> remainder2QuotientMap = new HashMap<>();
List<Long> remainders = new ArrayList<>();
while (longn != 0 && !remainder2QuotientMap.containsKey(remainder)) {
longn *= 10;
long quotient = longn/longd;
// Record the mapping from remainder to quotient
remainder2QuotientMap.put(remainder, quotient);
remainders.add(remainder);
remainder = longn%longd;
longn = remainder;
}
for (long r: remainders) {
if (r == remainder)
decimal.append("(");
decimal.append(remainder2QuotientMap.get(r));
}
if (longn == 0)
return decimal.toString();
else {
decimal.append(")");
return decimal.toString();
}
}
}
以下是C++的题解代码实现。
class Solution {
public:
string fractionToDecimal(int numerator, int denominator) {
if (numerator == 0)
return "0";
string decimal = "";
// Set the sign
if ((numerator > 0 && denominator < 0)
|| (numerator < 0 && denominator > 0)) {
decimal += "-";
}
// Avoid the overflow
long longn = numerator;
long longd = denominator;
longn = abs(longn);
longd = abs(longd);
// Calculate the integer part first
if (longn < longd) {
decimal += "0.";
}
else {
decimal += to_string(longn/longd);
longn = longn%longd;
if (longn == 0)
return decimal;
else
decimal += ".";
}
long remainder = longn;
unordered_map<long, long> remainder2quotient;
vector<int> remainders;
while (longn != 0 && remainder2quotient.count(remainder) <= 0) {
longn *= 10;
long quotient = longn/longd;
// Record
remainder2quotient[remainder] = quotient;
remainders.push_back(remainder);
remainder = longn%longd;
longn = remainder;
}
for (long r: remainders) {
if (r == remainder)
decimal += "(";
decimal += to_string(remainder2quotient[r]);
}
if (longn == 0)
return decimal;
else {
decimal += ")";
return decimal;
}
}
};