1. 程式人生 > 實用技巧 >【LeetCode-數學】分數到小數

【LeetCode-數學】分數到小數

題目描述

給定兩個整數,分別表示分數的分子 numerator 和分母 denominator,以字串形式返回小數。

如果小數部分為迴圈小數,則將迴圈的部分括在括號內。

示例:

輸入: numerator = 1, denominator = 2
輸出: "0.5"

輸入: numerator = 2, denominator = 3
輸出: "0.(6)"

題目連結: https://leetcode-cn.com/problems/fraction-to-recurring-decimal/

思路

模擬人做除法的情況。假設 c = a / b,r = a % b,如果餘數 r 不為 0,則將 r*10 後再次除以 b,如果餘數 r*10%b 不為 0,那麼將 r*10%b 乘以10接著除以 b,如果某一步的餘數為 0,則說明除法結束。如果某一步的餘數在之前出現過,則說明商出現了迴圈

所以,我們使用雜湊表記錄每一步餘數的位置 idx,如果出現了迴圈,則將左括號(插入到 idx,右括號)插入到結果的末尾。

程式碼如下:

class Solution {
public:
    string fractionToDecimal(int numerator, int denominator) {
        if(numerator==0) return "0";
        if(denominator==0) return "";

        long numer = long(numerator);  // 轉為 long,否則會溢位
        long denom = long(denominator);
        string ans = "";
        if(numer>0 && denom<0 || numer<0 && denom>0) ans += "-"; //是否同號
        numer = abs(numer); // 全轉為正數求解
        denom = abs(denom);

        long a = numer / denom; // a 是當前步的商的整數部分
        long r = numer % denom; // r 是當前步的餘數
        ans += to_string(a);
        if(r==0) return ans;

        unordered_map<int, int> lookup;  // 記錄餘數是否出現過
        ans += ".";
        int dotIdx = ans.size()-1; // 小數點出現的位置
        while(r && lookup.count(r)==0){
            lookup[r] = ++dotIdx;
            r*=10;
            ans+=to_string(r/denom);
            r%=denom;
        }
        if(lookup.count(r)==1){ // 餘數在之前出現過,出現迴圈
            ans.insert(lookup[r], "(");
            ans+=")";
        }
        return ans;
    }
};

參考

1、https://leetcode-cn.com/problems/fraction-to-recurring-decimal/solution/cmo-ni-ti-jian-dan-yi-dong-by-xiaoneng/
2、https://leetcode-cn.com/problems/fraction-to-recurring-decimal/solution/fen-shu-dao-xiao-shu-by-leetcode/