Leetcode 166 Fraction to Recurring Decimal 分數化小數

原題地址

https://leetcode.com/problems/fraction-to-recurring-decimal/

題目描述

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”.
給出 numerator = 1, denominator = 2, 返回 “0.5” 1/2=0.5.

Given numerator = 2, denominator = 1, return “2”.
給出 numerator = 2, denominator = 1, 返回 “2” 2/1=2.

Given numerator = 2, denominator = 3, return “0.(6)”.
給出 numerator = 2, denominator = 3, return “0.(6)” 1/3=0.(6).

解題思路

解題思路比較簡單,就是簡單的除法運算,每次運算獲取商和餘數,直到商爲0或者發現出現循環小數的情況。這裏需要注意的有以下幾點:

  1. 符號問題,輸入有可能是正數或負數,結果有正有負
  2. -0問題,分子爲0分母爲負數時,結果是0而不是-0
  3. 溢出問題,INT_MIN,可以使用[-1/-2147483648]和[-2147483648/-1]兩組數據來驗證是否解決了這個問題
  4. 循環小數,只把循環的部分放在括號內,可以使用[1/6]驗證是否解決了這個問題

計算過程

    0.16  
  |------
6 / 1.00
    0
   ---- 
    1 0       <-- 被除數=10, 在dividendCache[0]中記錄10.
    - 6
    ----  
      40      <-- 被除數=40, 在dividendCache[1]中記錄40.
    - 36 
     ----
       40      <-- 被除數=40, dividendCache[1]中已經記錄過40,因此從第1位小數開始是循環部分.

第1位小數是6,從dividendCache[1]起直到dividendCache[dividendCache.size()-1]的小數是循環部分,應當返回0.1(6)。

總體來說,這個題目並不難,只是各種邊界值可能搞瘋你,oj的平臺也有問題,同樣的代碼在c下過不了,說[-1/-2147483648 = 0.0000000004656612873077392578125]有錯,然而cpp可以通過。另外gcc環境下使用math.h時,編譯命令需要加入-lm,例如gcc main.c -o main -lm

代碼cpp

class Solution {
public:
    const static int CACHE_SIZE = 1000;
    /**
     * 分數轉換爲小數
     * @param numerator 分子
     * @param denominator 分母
     * @return 字符串
     * 如果小數部分是循環小數,用括號把循環部分包括起來
     */
    string fractionToDecimal(int numerator, int denominator) {
        if (numerator == 0) return "0";

        bool isNegative = numerator < 0 ^ denominator < 0; // 結果是否爲負數
        /* 處理爲正數 */
        double doubleNumerator = fabs(numerator);
        double doubleDenominator = fabs(denominator);
        double integral = floor(doubleNumerator / doubleDenominator); // 結果的整數部分
        doubleNumerator -= doubleDenominator * integral; // 餘數部分

        /* 計算並緩存計算結果 */
        int len = 0; // 小數部分長度
        string cache;// 小數部分緩存
        vector<double> dividendCache;
        bool isRecurring = false; // 是否是循環小數
        int recurringStart = 0; // 循環開始位
        int i = 0;
        while (doubleNumerator) { // 分子(餘數)不爲0時繼續計算
            doubleNumerator *= 10; // 被除數乘10
            len = dividendCache.size();
            for (i = 0; i < len; ++i) // 查詢是否構成循環(被除數是否已經存在過)
                if (dividendCache[i] == doubleNumerator) {
                    isRecurring = true; 
                    recurringStart = i;
                    break;
                }
            if (isRecurring) break; // 如果構成循環,結束計算
            i = (int)(floor(doubleNumerator / doubleDenominator)); // 商
            cache += '0' + i; // 記錄商
            dividendCache.push_back(doubleNumerator); // 記錄被除數
            doubleNumerator -= doubleDenominator * i; // 被除數取餘,作爲下次計算的被除數
        }

        /* 根據緩存數據生成返回數據 */
        /* 符號部分 */
        string ret = isNegative ? "-" : "";
        /* 整數部分 */
        string tmp;
        char c;
        if (integral == 0) ret += "0";
        else {
            while (integral) {
                c = (int)(integral - 10 * floor(integral / 10))+ '0';
                tmp = c + tmp;
                integral = floor(integral / 10);
            }
            ret += tmp;
        }
        /* 小數部分 */
        if (dividendCache.size() > 0) ret += '.';
        i = 0;
        if (isRecurring) {
            ret += cache.substr(0, recurringStart);
            ret += '(';
            ret += cache.substr(recurringStart);
            ret += ')';
        } else
            ret += cache;

        return ret;
    }
};

完整代碼https://github.com/Orange1991/leetcode/blob/master/166/cpp/main.cpp

測試數據

2 / 1 = 2
-2 / 1 = -2
1 / 2 = 0.5
1 / -2 = -0.5
1 / 3 = 0.(3)
-1 / 3 = -0.(3)
2 / 7 = 0.(285714)
-2 / 7 = -0.(285714)
1 / 11 = 0.(09)
-1 / -11 = 0.(09)
2147483647 / 27 = 79536431.(370)
-2147483647 / 27 = -79536431.(370)
2147483647 / 37 = 58040098.(567)
2147483647 / -37 = -58040098.(567)
1000 / 10 = 100
1000 / -10 = -100
1001 / 10 = 100.1
-1001 / 10 = -100.1
-2147483648 / 1 = -2147483648
-2147483648 / -1 = 2147483648
1 / 214748364 = 0.00(000000465661289042462740251655654056577585848337359161441621040707904997124914069194026549138227660723878669455195477065427143370461252966751355553982241280310754777158628319049732085502639731402098131932683780538602845887105337854867197032523144157689601770377165713821223802198558308923834223016478952081795603341592860749337303449725)
-1 / -2147483648 = 0.0000000004656612873077392578125
1 / -2147483648 = -0.0000000004656612873077392578125
-1 / -2147483648 = 0.0000000004656612873077392578125
1 / 6 = 0.1(6)

2015/8/4

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章