传送门
题目: 给定两个整数,分别表示分数的分子 numerator 和分母 denominator,以字符串形式返回小数。
如果小数部分为循环小数,则将循环的部分括在括号内。
输入: numerator = 1, denominator = 2 输出: “0.5”
输入: numerator = 2, denominator = 3 输出: “0.(6)”
- 需要用一个哈希表记录余数出现在小数部分的位置(实际上就是在ans里插入新计算的 商 的位置),
当发现余数重复了,就可以将重复出现的小数部分用括号括起来, 返回ans - 再出发过程中余数可能为 0,意味着不会出现循环小数,立刻停止程序。
并且要考虑 INT_MIN / -1
这种溢出的情况, 所以采用long 缓冲各个数值
public String fractionToDecimal(int numerator, int denominator) {
if (numerator == 0) return "0";
StringBuilder ans = new StringBuilder();
if (numerator < 0 ^ denominator < 0) ans.append('-');// 结果前边加负号
long a = Math.abs(Long.valueOf(numerator));// 两个结果缓冲成long且取绝对值
long b = Math.abs(Long.valueOf(denominator));
ans.append(String.valueOf(a / b)); // 整数部分加入ans
long mod = a % b;
if (mod == 0) return ans.toString(); // 整除了,直接返回
ans.append('.'); // 没有整除, 加入小数点
Map<Long, Integer> modMap = new HashMap<>(); // 商 -> 它添加到ans的位置
while (mod != 0) { // 还在循环, 如果没有循环小数, mod一定会变成0
if (modMap.containsKey(mod)) { // 余数重复出现,循环小数
ans.insert(modMap.get(mod), "(");// 把上一次插入的商位置前面插入(
ans.append(')'); // 在ans 尾插入 ), 把上次循环插入的商包起来
return ans.toString();
}
modMap.put(mod, ans.length());// 新的商 插入的位置是ans结尾,形成映射
mod *= 10; // 余数*10 继续除以除数b 得到 新的商和 新余数
ans.append(String.valueOf(mod / b)); // 除之后得到的商 加入ans
mod = mod % b; // 产生新余数
}
return ans.toString();
}
注意: 插入ans的是每一次的商
, 余数只是用来判断是不是循环了!