【一看就会一写就废 指间算法】分数到小数 —— 哈希表、长除数

47 阅读1分钟

指尖划过的轨迹,藏着最细腻的答案~

题目:

给定两个整数,分别表示分数的分子 numerator 和分母 denominator,以 字符串形式返回小数

如果小数部分为循环小数,则将循环的部分括在括号内。

如果存在多个答案,只需返回 任意一个

对于所有给定的输入,保证 答案字符串的长度小于 10410^4

示例 1:

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

示例 2:

输入:numerator = 2, denominator = 1
输出:"2"

示例 3:

输入:numerator = 4, denominator = 333
输出:"0.(012)"

提示:

  • 231numerator,denominator2311-2^{31} \leq numerator, denominator \leq 2^{31} - 1
  • denominator0denominator \neq 0

分析:

本题我们首先需要模拟长除法即可,假设商为q,余数为r,则除法运算如下:ab=q...r\frac{a}{b} = q...r,将q拼接如答案,接下来将r10b=q...r1,r=r1\frac{r * 10}{b} = q...r1, r = r1,根据上面公式,直到:

  • r == 0表示除尽;
  • 循环小数:怎样判断循环部分呢,我们可以使用哈希表来记录,keyrvalue下标,在再次出现r时,说明有循环,将r_to_pos[r]到当前下标使用括号括起来。

AC代码:

class Solution {
public:
    string fractionToDecimal(int numerator, int denominator) {
        long long a = numerator, b = denominator;
        string sign = a * b < 0 ? "-" : "";
        a = abs(a);
        b = abs(b);

        long long q = a / b, r = a % b;
        if (r == 0) {
            return sign + to_string(q);
        }

        string ans = sign + to_string(q) + ".";
        unordered_map<long long, int> r_to_pos = {{r, ans.size()}};
        while(r) {
            r *= 10;
            q = r / b;
            r %= b;
            ans += '0' + q;
            if (r_to_pos.contains(r)) {
                int poc = r_to_pos[r];
                return ans.substr(0, poc) + "(" + ans.substr(poc) + ")"; 
            }
            r_to_pos[r] = ans.size();
        }

        return ans;
    }
};