1. 程式人生 > 實用技巧 >LeetCode166. 分數到小數

LeetCode166. 分數到小數

要判斷是否會出現無限迴圈小數,就需要找迴圈節。

如果出現了迴圈節,會出現這樣一種情況:被除數除以除數的商,在之前已經出現過了,比如2 / 3,2比3小,借位,20 / 3 = 6 ... 2, 然後商又是6,6在之前出現過了,所以我們知道迴圈節就是6。

最終結果就是0.(6)。

要記錄之前已經出現過的商,我們就需要一個雜湊表記錄之前出現過的商,我們可以不斷做除法,直到整除或者出現迴圈節。

這道題測試用例有可能numerator是-2147483648(-231),而denominator是-1,這樣商就是2147483648(231),而int的最大值是2^31-1,因此可能會爆int,所以我們用long long來儲存中間計算結果。

程式碼如下:

class Solution {
public:
    string fractionToDecimal(int numerator, int denominator) {
        typedef long long LL;
        LL x = numerator, y = denominator;
        if(x % y == 0) {                        //如果整除,直接返回結果
            return to_string(x / y);
        }
        string res;
        if((x < 0) ^ (y < 0)) {                  //如果x和y中有且僅有1個是負數,則最終的商是負數
            res += '-';
        }
        x = abs(x), y = abs(y);
        res += to_string(x / y) + '.';            //計算出整數部分,不要忘了加上小數點
        x %= y;                                   
        unordered_map<LL, int> hash;              //雜湊表記錄當前的商在res字串中出現的位置,這是為了我們之後判斷重複和擷取迴圈節
        while(x != 0) {
            hash[x] = res.size();                 //記錄下當前這個商在res中的位置,方便之後根據res的下標擷取迴圈節
            x *= 10;                              //根據除法規則,被除數比除數小,向低位借位
            res += to_string(x / y);              
            x %= y;
            if(hash.count(x) != 0) {              //出現重複的商,說明找到了迴圈節,把迴圈節加上括號
                res = res.substr(0, hash[x]) + '(' + res.substr(hash[x]) + ')';      //res.substr(0, hash[x])是不迴圈部分,加上帶括號的迴圈節,就是最終答案
                break;
            }
        }
        return res;
    }
};