首先考虑一下符号,如果除数*被除数<0,最后结果以"-"开头。
然后把被除数和除数都取绝对值,直接整除,如果没有余数,加上符号位就可以返回了。
如果有余数的话,把刚刚得到的整数部分加上小数点。用一个map记录余数出现的次数,直到余数=0(能除尽)或者出现重复余数(循环小数)则结束,循环小数时需要在循环的部分前后加上()。
以例子来说明,-1/3,用sb来存储最终的答案,那么首先得到符号位是负号,然后1/3=0,证数部分就是0,余数为1,那么sb=-0.1。此时余数=1,然后就进入循环,先判断余数1在不在Map里,第一轮循环肯定不在,用cnt表示每个余数出现的次数,初始cnt=1,那么首先把余数1放到map里,map.put(1,cnt++)。然后为了得到sb下一位的值,我们希望是一个0-9的数,所以把余数*10=10,再除以除数,得到3就是这轮循环的结果,余数是1,此时sb就应该加上3,新的余数是1;第二轮循环,此时余数是1,发现已经在map里了,那么证明已经找到了循环小数的部分,就是3不停循环,sb此时=-0.3,已经不需要再加新的数了,我们希望结果是-0.(3),那么需要在循环小数部分的前后加上括号,后面的括号直接加在sb的结尾,前面的括号位置是从小数点开始数,到此轮循环出现的余数在Map里对应的value位置,map里第一轮循环放进去(1,1),因此左括号放在从小数点开始的第一位,得到结果,break循环,返回。
再举个例子,比如我们希望得到的结果是0.2(6),那么反向构造被除数和除数,应该是4/15,首先得到符号位和整数部分为0,然后余数为4,第一轮循环,先把(4,1)放入map,然后4*10/15=2余10,结果加2=0.2;第二轮循环,先把(10,2)放入map,然后10*10/15=6余10,结果加6=0.26;第三轮循环,此时余数为10,发现map里已经存在,说明找到了循环小数的部分,把10对应的value拿出来是2,说明左括号应该加在小数点开始第2位,右括号在最后一位,于是得到答案为0.2(6)
class Solution {
public String fractionToDecimal(int numerator, int denominator) {
StringBuilder sb = new StringBuilder();
long nn = (long) numerator;
long dd = (long) denominator;
if (nn * dd < 0) {
sb.append("-");
}
nn = Math.abs(nn);
dd = Math.abs(dd);
long intPart = nn / dd;
long left = nn % dd;
sb.append(intPart);
if (left == 0) {
return sb.toString();
}
Map<Long, Integer> map = new HashMap<>();
int cnt = 1;
sb.append(".");
while (left != 0) {
if (map.containsKey(left)) {
int dot = sb.indexOf(".");
sb.insert(dot + map.get(left), "(");
sb.append(")");
break;
} else {
map.put(left, cnt++);
left *= 10;
nn = left / dd;
left = left % dd;
sb.append(nn);
}
}
return sb.toString();
}
}