一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第27天,点击查看活动详情。
前言
力扣第166题 分数到小数 如下所示:
一、思路
题目意思很简单,就是输入一个小数(分子 + 分母的形式),输出计算后的小数。有如下的三种情况:
- 正好整除,则返回一个整数。例如
4 / 2 = 2 - 可以除尽的有限小数。如
3 / 2 = 1.5 - 除不尽的无线循环小数。如
1 / 3 = 0.(3)
一二两种情况都很好处理,只需要简单的使用除法即可。如何通过计算知道一个分数是无线循环小数呢?在这里我们先以示例中的 4 / 333 为例子分析,模拟计算的步骤人如下所示:
ret:表示小数结果
- 因为
4 < 333,先将分子扩大100倍,即400 / 333(后面再除100) 400 / 333 = 1...67,余数为67。此时ret = 0.01670 / 333 = 2...4,余数为4。此时ret = 0.01240 < 333,故上零。此时ret = 0.0120400 / 333 = 1...67,余数为67。此时ret = 0.01201
我们发现在第五步中的 除数 和 被除数,400/333 在前面的步骤中是出现过的,也就是说这个小数是无限循环小数。但是实际上第四步中的 40 / 333 已经出现过了,也就是说循环的部分为 012,即小数为 0.(012)
综上所述,我们在处理的过程模拟以上的过程即可。大致分为以下几步:
- 如过可以整除,则返回结果即可
- 使用
哈希表存储小数计算过程中的被除数,如果出现了相同的被除数说明出现了循环。返回正确的小数字符串即可
二、实现
实现代码
public String fractionToDecimal(int numerator, int denominator) {
long divisor = numerator; // 被除数
long dividend = denominator; // 除数
// 整数
if (divisor % dividend == 0) {
return String.valueOf(divisor / dividend);
}
StringBuilder sb = new StringBuilder();
if (divisor * dividend < 0) {
sb.append('-');
}
divisor = Math.abs(divisor);
dividend = Math.abs(dividend);
// 整数部分
sb.append(divisor / dividend).append('.');
// 小数部分
StringBuilder decimal = new StringBuilder();
Map<Long, Integer> map = new HashMap<>(); // 存储被除数
long remainder = divisor % dividend;
int index = 0;
while (remainder != 0 && !map.containsKey(remainder)) {
map.put(remainder, index);
remainder *= 10;
decimal.append(remainder / dividend);
remainder = remainder % dividend ;
index++;
}
if (remainder != 0) { // 有循环节
int p = map.get(remainder);
decimal.insert(p, '(');
decimal.append(')');
}
sb.append(decimal);
return sb.toString();
}
测试代码
public static void main(String[] args) {
new Number166().fractionToDecimal(4, 333);
}
结果
三、总结
感谢看到最后,非常荣幸能够帮助到你~♥
如果你觉得我写的还不错的话,不妨给我点个赞吧!如有疑问,也可评论区见~