【数学】分数到小数 巧用MAP获取循环小数

题目描述

给定两整数,分别表示分数的分子(numerator)和分母(denominator),请使用字符串形式返回小数。

如果小数为循环小数,则将循环的部分括在括号里面。对应给定的输入,保证答案字符串长度小于10000;

示例1:

输入:numerator = 4, denominator = 333
输出:"0.(012)"

解题思路 

这道题是:求小数(余数+求商)+找到循环小数。


对于求小数(余数+求商), 有以下操作流程:

  1. 使用numerator/denominator获得value,这个value就是每一位的小数值;
  2. 使用numerator%denominator获得mod,再将mod * 10 就是下一位要做计算的 numerator;
  3. 最后循环1和2操作就能计算出小数结果。

对于找到循环小数,有以下操作流程:

  1. 初始化一个modMap,用于记录取模计算mod对应的字符串位置;
  2. 循环代码,判断modMap中是否存在mod如果存在则直接跳出循环;
  3. 使用numerator%denominator获得mod,设置modMap。

最后是对结果的组装,如果有循环小数则需要组装循环小数,如果没有则直接返回结果。这里组装循环小数是使用了StringBuilder.insert()函数,避免拷贝数据带来的性能损耗。

代码实现


import java.util.HashMap;
import java.util.Map;

class Solution {
    public String fractionToDecimal(int numerator, int denominator) {
        // 类型强转,避免溢出
        return fractionToDecimal((long) numerator, (long) denominator);
    }

    public String fractionToDecimal(long numerator, long denominator) {

        // 数据预先处理,先获得整数部分,并且确定符号类型
        long v = numerator / denominator;
        StringBuilder sb = new StringBuilder(10);
        if (v == 0) {
            if (numerator > 0 && denominator < 0 || numerator < 0 && denominator > 0) {
                sb.append("-");
            }
            sb.append('0');
        } else {
            sb.append(v);
        }

        numerator = Math.abs(numerator % denominator);
        if (numerator != 0) {
            sb.append(".");
        }
        denominator = Math.abs(denominator);


        int start = sb.length();
        // 创建modMap记录每个mod的位置
        Map<Long, Integer> modMap = new HashMap<>();
        while (numerator != 0 && modMap.get(numerator) == null) {

            //记录每个mod的位置
            modMap.put(numerator, start);

            // 计算分数
            numerator *= 10;
            sb.append(numerator / denominator);

            // 重新生成分子
            numerator %= denominator;
            start++;
        }

        // 判断是否存在循环小数
        Integer index = modMap.get(numerator);
        if (index != null) {
            // 使用insert操作,降低耗时
            sb.insert(index.intValue(), '(').append(')');
        }
        return sb.toString();
    }

    public static void main(String[] args) {
        Solution solution = new Solution();
        System.out.println(solution.fractionToDecimal(4, -333));
        System.out.println(solution.fractionToDecimal(4, 333));
        System.out.println(solution.fractionToDecimal(1, 2));
        System.out.println(solution.fractionToDecimal(2, 1));
        System.out.println(solution.fractionToDecimal(2, -1));
    }

}

总结

这道题就是一个数学题目,我主要的时间花在判断循环小数上,最终还是看了其他人的解决思路后才做出来的。

这个过程中遇到2个问题,一个是溢出问题,所以我这边最后使用long做计算。还有就是耗时问题,我开始是重新拷贝字符串再拼接循环小数,这样导致耗时很高,最后使用StringBuilder.insert耗时才降下来的。后续还是要多看看系统自带库函数,目前看都比自己实现的性能要好很多。如果有性能更好,设计更好的解决方案,欢迎回复。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值