leetcode 166.分数到小数

这篇博客主要探讨LeetCode 166题的解决方案,重点在于分数转换成小数时如何判断并处理循环小数。通过分析整数和小数部分的求解,博主提出利用映射关系来确定循环体,避免了简单地以numera是否等于0作为循环结束的条件。文章通过实例展示了数据扩位、异号修正以及小数部分的循环判断思路。
摘要由CSDN通过智能技术生成

leetcode 166.分数到小数


给定两个整数,分别表示分数的分子 numerator 和分母 denominator,
以字符串形式返回小数。如果小数部分为循环小数,则将循环的部分括在括号内。

示例 1:
输入: numerator = 1, denominator = 2
输出: "0.5"

示例 2:
输入: numerator = 2, denominator = 1
输出: "2"

示例 3:
输入: numerator = 2, denominator = 3
输出: "0.(6)"


思路最重要:

初次分析:

将结果分为整数部分和小数部分,整数部分好求(numerator/denominator即可)

  • 小数的计算过程,小数部分可定义为StringBuilder decimal = new Stringbuilder()
    • 计算numerator=numerator%denominator
      • numerator *=10
      • numerator=0
        • 表明小数部分结束,我们需要返回计算结果decimal
      • numerator!=0
        • 表明小数部分未结束,将numerator/denominator添加到小数的计算结果,即decimal.append(numerator/denominator);
          numerator/denominator==0(解决小数部分中会出现0值的情况);
          判断是否能在decimal从后往前查找到值numerator/denominator,并且numerator/denominator的不为0(解决循环小数的问题,之所以加一个判断条件最后一个字符不为0,是因为防止出现小数的计算结果出现连续0的情况,如不加出现.00...时,结果就会矛盾);若能找到,取出循环子串,与()进行拼接,返回计算结果
        • 在小数的循环部分出现0时如何解决?
      • 继续计算numerator=numerator%denominator,开始下一轮循环

再次分析:

经过实际实现时的再次分析,发现本题有许多需要注意的地方,但是整体思路还是与初次的分析的思路保持不变。

整数部分的求解:
  • 整数部分的求解不能轻视。其一,结果有正负之分,其二,数据是否会溢出需要提前在此进行处理。方案如下:

    • 数据扩位:
    	long numera = numerator;
        long denomina = denominator;
    
    • 异号修正:
    	String integerPart = "";
        if((numera^denomina)<0){
            integerPart += "-";
            numera = Math.abs(numera);
            denomina = Math.abs(denomina);
        }
        integerPart += numera/denomina;
    

    促使我进行上述操作的一个例子:

    -2147483648/1
    

小数部分的求解:
  • 此步的思路与初次分析的思路差不多,循环的整体架构如下。若被除数numera小于除数denomina,将除数乘以10,在除以被除数即可得到一个小数部分的结果,当被除数numera模除数denomina即整除时,小数部分就结束了。
	while((numera=numera%denomina)!=0){
            numera = numera*10;
            long num = numera/denomina;
            ...
            ...
            ...
    }
  • 显然,上述的操作可以处理非循环小数,但是循环小数怎么处理呢?这是一个关键。读者可以看到,我的初次分析是以num是否等于0为标准,来确定循环部分,但是当我想到这两个反例时,便放弃了此想法。
反例1:
1/110  = 0.0(09)
反例2:
1/333  = 0.(003)
  • 以反例1为例,当计算结果为0.0090,此时以最后一个零为界限,利用字符串的decimalPart.toString().lastIndexOf从后往前确定循环部分为(09),结果正确;反例2呢?当计算结果为0.0030,循环部分就确定为(03),结果错误,利用indexOf从前往后找,两者结果的正确性同样不一致。
我们可以换一种思路去确定循环体,小数部分之所以会有循环体,根本原因是被除数numera在循环中重复出现了(也就是说,numera的重复出现,使得小数部分也重复出现,因此循环)抓住这一点,不攻自破。利用map存储每次得到的被除数numera与decimalPart得到的小数的索引的映射关系,当map.contains(numera)为真时,表明之前循环中出现了numera,由此确定循环部分。

代码不重要:

class Solution {
    public String fractionToDecimal(int numerator, int denominator) {
        if(numerator==0) return 0+"";
        long numera = numerator;
        long denomina = denominator;
        String integerPart = "";
        if((numera^denomina)<0){
            integerPart += "-";
            numera = Math.abs(numera);
            denomina = Math.abs(denomina);
        }
        integerPart += numera/denomina;
        
        if(numerator%denomina==0) return integerPart;
        
        StringBuilder decimalPart = new StringBuilder(".");
        Map<Long,Integer> map = new HashMap<>();
        int i=1;
        
        while((numera=numera%denomina)!=0){
            numera = numera*10;
            long num = numera/denomina;
            String tmp = decimalPart.toString();
            if(map.containsKey(numera)){
                int index = map.get(numera);
                return integerPart +tmp.substring(0,index)+"("+tmp.substring(index)+")"; 
            }else{
                map.put(numera,i);
            }
            decimalPart.append(""+num);
            i++;
        }
        return integerPart + decimalPart.toString();
    }
}

学习了别人的解法,进行优化后:

class Solution {
    public String fractionToDecimal(int numerator, int denominator) {
        if(numerator==0) return 0+"";
        long numera = numerator;
        long denomina = denominator;
        StringBuilder res = new StringBuilder();
        if((numera^denomina)<0){
            res.append("-");
            numera = Math.abs(numera);
            denomina = Math.abs(denomina);
        }
        res.append(numera/denomina);
        if(numerator%denomina==0) return res.toString();
        res.append(".");
        
        Map<Long,Integer> map = new HashMap<>();
        while((numera=numera%denomina)!=0){
            numera = numera*10;
            long num = numera/denomina;
            if(map.containsKey(numera)){
                res.insert(map.get(numera),"(");
                res.append(")");
                return res.toString(); 
            }
            map.put(numera,res.length());
            
            res.append(""+num);
        }
        return res.toString();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值