標籤:fraction to recurrin 分數轉小數 leetcode
【題目】
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)".
【題意】
給定一個分子和一個分母,以字串的形式返回該小數。如果小數無限迴圈的話,用括弧擴住迴圈體。
【官方Solution】
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.
【中文解析】
痛點:如何識別迴圈體?
解決方案:用一個HashMap記錄每一個餘數,當出現重複的餘數時,那麼將會進入迴圈,兩個重複餘數之間的部分就是迴圈體。
樣本:1/13=0.076923076923076923...,當小數部分第二次出現0時,就意味著開始了迴圈,那麼需要把076923用括弧括起來,結果為0.(076923)。
涉及技巧:1)在不斷相除的過程中,把餘數乘以10再進行下一次相除,保證一直是整數相除;2)HashMap的key和value分別是<當前餘數, 對應結果下標>,這樣擷取076923時就可根據value值來找。
注意點1:考慮正負數,先判斷符號,然後都轉化為正數;
注意點2:考慮溢出,如果輸入為Integer.MIN_VALUE,取絕對值後會溢出。
代碼中已添加註釋,來看代碼:
public class Solution { public String fractionToDecimal(int numerator, int denominator) { if (numerator == 0) return "0"; if (denominator == 0) return ""; String ans = ""; //如果結果為負數 if ((numerator < 0) ^ (denominator < 0)) { ans += "-"; } //下面要把兩個數都轉為正數,為避免溢出,int轉為long long num = numerator, den = denominator; num = Math.abs(num); den = Math.abs(den); //結果的整數部分 long res = num / den; ans += String.valueOf(res); //如果能夠整除,返回結果 long rem = (num % den) * 10; if (rem == 0) return ans; //結果的小數部分 HashMap<Long, Integer> map = new HashMap<Long, Integer>(); ans += "."; while (rem != 0) { //如果前面已經出現過該餘數,那麼將會開始迴圈 if (map.containsKey(rem)) { int beg = map.get(rem); //迴圈體開始的位置 String part1 = ans.substring(0, beg); String part2 = ans.substring(beg, ans.length()); ans = part1 + "(" + part2 + ")"; return ans; } //繼續往下除 map.put(rem, ans.length()); res = rem / den; ans += String.valueOf(res); rem = (rem % den) * 10; } return ans; }}
Java編程誤區:一定要先把 int 轉為 long,然後再取絕對值。如果寫成 long num = Math.abs(numerator) 就會有問題,因為這句代碼在 numerator=Integer.MIN_VALUE 時相當於 long num = Math.abs(-2147483648),這樣得到的 num還是 -2147483648。
參考來源1:http://www.cnblogs.com/ganganloveu/p/4170601.html
參考來源2:https://oj.leetcode.com/discuss/18780/my-java-solution-with-explanation-second-version
【LeetCode】Fraction to Recurring Decimal【Solution】