链接:
https://leetcode.com/problems/fraction-to-recurring-decimal/
大意:
给定两个整数n和d,分别作为分子和分母,求出 n/d的小数形式,当小数有循环体时,使用“()”将循环体包围起来。例子:
思路:
解决此问题,主要需要注意以下几点:
- 结果是否为0。即n是否等于0,若等于0,则直接返回"0"
- 可能出现整型溢出,所以需要将两个整数先转成long型,记为nLong,dLong
- 判断结果的正负。可以判断 nLong * dLong的正负来知道除法的正负。之后便是使用 abs(nLong) 与 abs(dLong)来进行计算
- 怎样获得小数部分:模拟一般除法运算,都是余数乘10(作为新的被除数)除以除数dLong,得到一个商;余数乘10模(取余)除数dLong,得到下一阶段的被除数。如果没有循环体,则最终余数肯定是0
- 如果有循环体:则可以对于小数部分的每一个数(商),我们记录这个商所对应的余数(即这个商是有哪个被除数得来的)以及该商在小数部分的位置(0,1,2,...),将其put进一个map中保存。当再出现一个余数rem已经出现在map.keys()中,则表明循环体为map.get(rem)到当前余数小数部分末尾。
具体实现见如下代码。
代码:
class Solution {
public String fractionToDecimal(int n, int d) {
if (n == 0)
return "0";
boolean positive = true;
// 为解决整型越界的问题 将int转为long
long nLong = (long)n, dLong = (long)d;
// 判断正负
if (nLong * dLong < 0L)
positive = false;
nLong = Math.abs(nLong);
dLong = Math.abs(dLong);
// System.out.println(nLong);
long intPart = nLong / dLong, rem = nLong % dLong; // 得到整数部分 和 余数
if (rem == 0)
return positive ? Long.toString(intPart) : "-" + Long.toString(intPart);
StringBuilder sb = new StringBuilder(); // 得到小数部分 可能含有"()"
Map<Long, Integer> map = new HashMap<>(); // 存储余数rem和rem / d所在的StringBuilder中的位置
// 当余数为0 或者 map中出现过该余数时,跳出循环
int index = 0;
while (rem != 0L && !map.containsKey(rem)) {
map.put(rem, index++);
nLong = rem * 10; // 模拟除法
rem = nLong % dLong;
sb.append(nLong / dLong);
}
if (rem == 0) {
String res = intPart + "." + sb.toString();
return positive ? res : "-" + res;
}
sb.insert(map.get(rem), "(");
sb.append(")");
String res = intPart + "." + sb.toString();
return positive ? res : "-" + res;
}
}
结果:
结论:
有幸能再遇到考研机试题的最后一题,当时考研用的是C语言,里面很多数据结构都没有现成的,需要自己造轮子(当然当时也是菜的不知道map是什么东西)。。。现在能使用时间和空间效率都不错的方法解决,还是挺欣慰的。。。