题目:
给定两个整数,分别表示分数的分子 numerator 和分母 denominator,以 字符串形式返回小数 。
如果小数部分为循环小数,则将循环的部分括在括号内。
如果存在多个答案,只需返回 任意一个 。
对于所有给定的输入,保证 答案字符串的长度小于 104 。
示例 1:
输入:numerator = 1, denominator = 2
输出:"0.5"
示例 2:
输入:numerator = 2, denominator = 1
输出:"2"
示例 3:
输入:numerator = 4, denominator = 333
输出:"0.(012)"
提示:
-231 <= numerator, denominator <= 231 - 1
denominator != 0
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/fraction-to-recurring-decimal
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路:
模拟:
1.首先需要将分子分母转换成long类型。因为分子分母起初均为int类型,当numerator = −231 和 denominator = -1时,计算结果为231,超出 int 的范围 [-231, 231 - 1];
2.将分数计算出小数拆解成三个问题:
- 确定小数的正负号:将分子分母相乘,如果计算结果小于0,则先往答案头部加一个 “-” 号;
- 确定小数的小数点前面的整数:分子/分母整数相除的结果就为小数点前面的整数,整除得到的整数部分可能为0;
- 确定小数的小数点后的有限小数或无限循环小数:模拟数学中除法的计算过程,不断对余数补0(乘10),再重新计算余数和除数的新余数
- 如果在某一步出现分子能与分母整除,则是有限小数;
- 一旦出现之前出现过的余数,说明产生了循环小数,则使用哈希表存储余数最早出现的位置,出现相同余数时,则将左括号插入到循环小数的开始位置,然后在循环小数结尾加上右括号,这样括号内的数即为循环小数部分。
java代码:
1 class Solution { 2 public String fractionToDecimal(int numerator, int denominator) { 3 //将分子分母转换成long 4 long a = numerator, b = denominator; 5 //如果本身能够整除,直接返回计算结果 6 if(a % b == 0) return String.valueOf(a / b); 7 StringBuilder sb = new StringBuilder(); 8 //如果分子分母异号,直接追加一个负号 9 if(a * b < 0) sb.append('-'); 10 //取分子分母的绝对值 11 a = Math.abs(a); 12 b = Math.abs(b); 13 //计算小数点前面的整数 14 sb.append(String.valueOf(a/b) + "."); 15 //将余数赋值给a 16 a %= b; 17 Map<Long, Integer> map = new HashMap<>(); 18 //记录当前余数的开始位置,并继续模拟除法 19 while(a != 0 && !map.containsKey(a)){ 20 map.put(a, sb.length()); 21 a *= 10; 22 sb.append(a / b); 23 a %= b; 24 } 25 if(a == 0) return sb.toString(); 26 return sb.insert(map.get(a).intValue(), '(').append(')').toString(); 27 } 28 }
小知识:
StringBuilder insert(int offset, char c):在此序列中插入 char参数的字符串表示形式。
offset 表示字符插入的位置,该位置元素(包括该位置的元素)及之后字符串往后移
例如:如果z引用当前内容为“ start ”的字符串构建器对象,那么z.insert(4, “le”)会将字符串构建器更改为包含“ starlet ”。