leetcode:166. 分数到小数

题目来源

题目描述

在这里插入图片描述

题目解析

  • 不能直接相除,因为无法区分循环小数。
  • 将分数转成整数或者小数,做法是计算分子和分母相除的结果。可能的结果有三种:整数、小数、无限循环。
  • 首先可以明确,两个数相除要么是「有限位小数」,要么是「无限循环小数」,而不可能是「无限不循环小数」。
  • 问题是怎么区分[无限循环小数]与[有限位小数]呢?关键点在于循环,可以用unordered_map记录某个小数是否出现过,如果出现过,就说明出现了循环。
    在这里插入图片描述

如下:

  • 判断正负,利用分子分母相乘符号判断;
  • 确定整数部分,判断有无小数部分;
  • 看小数部分是否有重复:小数部分用map来存储每次的余数的位置,一旦重复,说明有循环,跳出,否则直到余数为0退出;
  • 防止整型溢出,使用long,注意 INT_MIN

模拟

将分数转成整数或者小数,做法是计算分子和分母相除的结果。可能的结果有三种:整数、小数、无限循环。

  • 如果分子可以被分母整除,那么结果是小数。将分子除以分母的商以字符串的形式返回即可。比如2/1 = 2
  • 如果分子不可以被分母整除,则结果是有限小数或无限循环小数,需要通过模拟长除法的方式计算结果。

关于长除法:

  • 为了方便处理,首先根据分子和分母的正负决定结果的正负(注意此时分子和分母都不为 0),然后将分子和分母都转成正数,再计算长除法。

计算长除法时,首先计算结果的整数部分,将下面部分依次拼接到结果中:

  • 如果结果是负数则将负号拼接到结果中,如果是正数则跳过这一步
  • 将整数部分拼接到结果中
  • 将小数点拼接到结构中

完成上面拼接之后,根据余数计算小数部分

  • 计算小数部分时,每次将余数乘以 10,然后计算小数的下一位数字,并得到新的余数。重复上述操作直到余数变成 00 或者找到循环节。
    • 如果余数变成 0,则结果是有限小数,将小数部分拼接到结果中。
    • 如果找到循环节,则找到循环节的开始位置和结束位置并加上括号,然后将小数部分拼接到结果中。
  • 如何判断是否找到循环节?注意到对于相同的余数,计算得到的小数的下一位数字一定是相同的,因此如果计算过程中发现某一位的余数在之前已经出现过,则为找到循环节。为了记录每个余数是否已经出现过,需要使用哈希表存储每个余数在小数部分第一次出现的下标。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#include <cstdlib>
#include <cstring>
#include <vector>
#include <iostream>
#include <map>
#include <unordered_map>
using namespace std;
class Solution {
public:
    string fractionToDecimal(int numerator, int denominator) {
        long a = numerator, b = denominator;
        // 1. 如果本身能够整除,直接返回计算结果
        if(a % b == 0){
            return std::to_string(a / b);
        }

        //2. ----
        std::string ans;
        if(a * b < 0){   // 如果其一为负数,先追加负号
            ans.push_back('-');
        }

        a = std::abs(a), b = std::abs(b);

        // 整数部分
        ans.append(std::to_string(a / b) + ".");    // 计算小数点前的部分,并将余数赋值给 a


        // 小数部分
        std::map<int, int> map ;
        a = a % b;
        while (a != 0){
            map.insert({a, ans.length()});
            a = a * 10;
            ans.append(std::to_string(a / b));
            a = a % b;
            if(map.count(a)){    // 如果当前余数之前出现过,则将 [出现位置 到 当前位置] 的部分抠出来(循环小数部分)
                int u = map[a];
                std::string t;
                t.append(ans.substr(0, u ) + "(")
                    .append(ans.substr(u , ans.size() - u) + ")");
                return t;
            }
        }

        return ans;
    }
};

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值