分数到小数--通过找寻出现重复余数的情况

题目

在这里插入图片描述

解题分析

首先什么是循环小数?循环小数都存在一个循环节,后面的小数部分都是根据循环节来循环的,如何得到循环节?这就是下面讨论的问题。
在这里插入图片描述

  1. 失败例子:用的每次得到的小数结果作备忘录记录,然而,明显这个重复无法作为循环是否开始的标志
  2. 比如1/333=0.003-003循环,按上面的方式就变成了0的循环。
  3. 正确的应该记录每次除法的余数,这样尝试num%333=>1->10->100->1找到循环点。
    这就是找寻循环节的正确方法,看是否出现余数循环即可,如果余数为0就是可以除的断,如果出现重复就是循环。

简而言之就是,如果除法过程中出现前面已经出现过的余数,那么就相当于后面的除法结果肯定和之前的处理是一模一样的,遂为循环。

错误代码示范

class Solution {
public:
    string fractionToDecimal(int numerator, int denominator) {
        //处理特殊情况
        if(numerator==INT_MIN&&denominator==-1){
            return to_string((long long)numerator/denominator);
        }
        string res = "";
        if(numerator==0)
            return "0";
        if(denominator==0)
            return res;
        //得到符号,因为取模运算需要全为正数
        if((numerator^denominator)<0)res.push_back('-');
        long long t_num = numerator>0?numerator:~((unsigned int)numerator-1);
        long long t_denom = denominator>0?denominator:~((unsigned int)denominator-1);
        //处理整数部分
        res += to_string(t_num/t_denom);

        
        int newNum = t_num%t_denom;
        if(!newNum)//若newNum为0则说明被整除无小数部分,可以直接返回了
            return  res;    
        //处理小数部分,得到非假分数开始模拟小数除法
        res.push_back('.');
        //用自建数组记录下标出现重复小数部分,一旦出现重复跳出循环开始在对应 位置打上括号
        int t_float = newNum*10/t_denom;
        res += to_string(t_float);
        newNum = newNum*10%t_denom;
        int visit[10];
        memset(visit,0,sizeof(visit));
        while(newNum&&visit[t_float]==0){
            visit[t_float] = res.size()-1;
            t_float = newNum*10/t_denom;
            res += to_string(t_float);
            newNum = newNum*10%t_denom;
        }if(newNum&&visit[t_float]){
            res.pop_back();
            res.insert(visit[t_float],"(");
            res.push_back(')');
        }
    return res;
}
};

正确代码

class Solution {
public:
    string fractionToDecimal(int numerator, int denominator) {
        //处理特殊情况
        if(numerator==INT_MIN&&denominator==-1){
            return to_string((long long)numerator/denominator);
        }
        string res = "";
        if(numerator==0)
            return "0";
        if(denominator==0)
            return res;
        //得到符号,因为取模运算需要全为正数
        if((numerator^denominator)<0)res.push_back('-');//下面根据是否为正数,统一转正数(用的负数补码转正数原码的方法(注意一定要用无符号转化,否则会出现10000000...-1仍然是INT_MIN(爆了)))
        long long t_num = numerator>0?numerator:~((unsigned int)numerator-1);
        long long t_denom = denominator>0?denominator:~((unsigned int)denominator-1);
        //处理整数部分
        res += to_string(t_num/t_denom);  
        long long newNum = t_num%t_denom;//注意用long long防止后面可能会int溢出
        if(!newNum)//若newNum为0则说明被整除无小数部分,可以直接返回了
            return  res;    
        //处理小数部分,得到非假分数开始模拟小数除法
        res.push_back('.');
        //用hash表记录余数和余数此时对应的除法结果对应的下标,一旦出现重复的余数便是出现循环小数
        int index = res.size();
        unordered_map<int,int>visit;
        while(newNum&&visit.count(newNum)==0){
            visit[newNum] = index++;
            newNum *= 10;
            res += to_string(newNum/t_denom);
            newNum = newNum%t_denom;
        }if(visit.count(newNum)){
            res.insert(visit[newNum],"(");
            res.push_back(')');
        }
    return res;
}
};

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值