Fraction to Recurring Decimal
Long-divide numerator by denominator and wrap the repeating cycle in parentheses.
Problem#
Given numerator and denominator integers, return the fraction as a string. If the fractional part repeats, enclose the repeating block in parentheses.
Examples#
1/2→"0.5".2/1→"2".4/333→"0.(012)".1/6→"0.1(6)".
Constraints#
-2^31 <= num, den <= 2^31 - 1,den != 0.
Hints#
Hint
Approach#
Handle sign and integer part. For the fractional part, simulate long division: at each step, multiply remainder by 10, append rem / den as a digit, set rem = rem % den. A repeated remainder means the cycle restarts there — insert ( at the recorded position and append ).
Solution#
class Solution {public: string fractionToDecimal(int numerator, int denominator) { if (numerator == 0) return "0"; string ans; long long num = numerator, den = denominator; if ((num < 0) ^ (den < 0)) ans.push_back('-'); num = abs(num); den = abs(den); ans += to_string(num / den); long long rem = num % den; if (rem == 0) return ans; ans.push_back('.'); unordered_map<long long, int> seen; while (rem != 0) { auto it = seen.find(rem); if (it != seen.end()) { ans.insert(it->second, "("); ans.push_back(')'); break; } seen[rem] = ans.size(); rem *= 10; ans += to_string(rem / den); rem %= den; } return ans; }};import ( "strconv" "strings")
func fractionToDecimal(numerator int, denominator int) string { if numerator == 0 { return "0" } var sb strings.Builder num := int64(numerator) den := int64(denominator) if (num < 0) != (den < 0) { sb.WriteByte('-') } if num < 0 { num = -num } if den < 0 { den = -den } sb.WriteString(strconv.FormatInt(num/den, 10)) rem := num % den if rem == 0 { return sb.String() } sb.WriteByte('.') seen := map[int64]int{} ans := sb.String() for rem != 0 { if pos, ok := seen[rem]; ok { return ans[:pos] + "(" + ans[pos:] + ")" } seen[rem] = len(ans) rem *= 10 ans += strconv.FormatInt(rem/den, 10) rem %= den } return ans}class Solution: def fractionToDecimal(self, numerator: int, denominator: int) -> str: if numerator == 0: return "0" parts = [] if (numerator < 0) ^ (denominator < 0): parts.append('-') num, den = abs(numerator), abs(denominator) parts.append(str(num // den)) rem = num % den if rem == 0: return ''.join(parts) parts.append('.') seen = {} frac = [] while rem != 0: if rem in seen: idx = seen[rem] frac.insert(idx, '(') frac.append(')') break seen[rem] = len(frac) rem *= 10 frac.append(str(rem // den)) rem %= den return ''.join(parts) + ''.join(frac)var fractionToDecimal = function(numerator, denominator) { if (numerator === 0) return "0"; const parts = []; if ((numerator < 0) !== (denominator < 0)) parts.push('-'); let num = Math.abs(numerator), den = Math.abs(denominator); parts.push(String(Math.floor(num / den))); let rem = num % den; if (rem === 0) return parts.join(''); parts.push('.'); const seen = new Map(); let frac = ''; while (rem !== 0) { if (seen.has(rem)) { const idx = seen.get(rem); frac = frac.slice(0, idx) + '(' + frac.slice(idx) + ')'; break; } seen.set(rem, frac.length); rem *= 10; frac += String(Math.floor(rem / den)); rem %= den; } return parts.join('') + frac;};class Solution { public String fractionToDecimal(int numerator, int denominator) { if (numerator == 0) return "0"; StringBuilder ans = new StringBuilder(); long num = numerator, den = denominator; if ((num < 0) ^ (den < 0)) ans.append('-'); num = Math.abs(num); den = Math.abs(den); ans.append(num / den); long rem = num % den; if (rem == 0) return ans.toString(); ans.append('.'); Map<Long, Integer> seen = new HashMap<>(); while (rem != 0) { if (seen.containsKey(rem)) { int pos = seen.get(rem); ans.insert(pos, '('); ans.append(')'); break; } seen.put(rem, ans.length()); rem *= 10; ans.append(rem / den); rem %= den; } return ans.toString(); }}function fractionToDecimal(numerator: number, denominator: number): string { if (numerator === 0) return "0"; const parts: string[] = []; if ((numerator < 0) !== (denominator < 0)) parts.push('-'); let num = Math.abs(numerator), den = Math.abs(denominator); parts.push(String(Math.floor(num / den))); let rem = num % den; if (rem === 0) return parts.join(''); parts.push('.'); const seen = new Map<number, number>(); let frac = ''; while (rem !== 0) { if (seen.has(rem)) { const idx = seen.get(rem)!; frac = frac.slice(0, idx) + '(' + frac.slice(idx) + ')'; break; } seen.set(rem, frac.length); rem *= 10; frac += String(Math.floor(rem / den)); rem %= den; } return parts.join('') + frac;}Editorial#
Long division produces a repeating remainder iff the fraction is non-terminating, and the cycle starts at exactly the first re-seen remainder. The hash map remembers each remainder’s output position, so the moment we revisit one we know where to insert (. Using long long avoids overflow on INT_MIN / -1 and on the abs of INT_MIN.
Complexity#
- Time: O(D) — at most
dendistinct remainders before a cycle. - Space: O(D).
Concept revision#
Related#