「前端刷题」166.分数到小数(MEDIUM)

138 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第12天,点击查看活动详情

题目(Fraction to Recurring Decimal)

链接:https://leetcode-cn.com/problems/fraction-to-recurring-decimal
解决数:446
通过率:33.3%
标签:哈希表 数学 字符串 
相关公司:goldman-sachs airbnb google 

给定两个整数,分别表示分数的分子 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

思路

  1. 先全部转化成正数
  2. 记录余数出现的位置,如果下次再重复,则说明循环了
/**
 * @param {number} numerator
 * @param {number} denominator
 * @return {string}
 */
var fractionToDecimal = function(numerator, denominator) {
    if(numerator === '0') return '0';
    let ans = '';
    let map = new Map();
    let a = Math.abs(numerator);
    let b = Math.abs(denominator);
    let c = Math.floor(a / b);// 数字比较大的时候位运算会出问题 -2147483648 和 1
    let d = a % b;
    if((numerator > 0 && denominator < 0) || (numerator < 0 && denominator > 0) )  {
        ans = ans.concat('-')
    }
    ans = ans.concat(c);
    if(d === 0) return ans;
    ans = ans.concat('.');
    while(d !== 0) {
        if(map.has(d)) {
            ans = insert('(',map.get(d),ans);
            ans = ans.concat(')');
            return ans;
        }
        map.set(d,ans.length);
        d *= 10;
        ans = ans.concat(d/b | 0);
        d = d % b;
    }
    return ans;
}
const insert = function(str,pos,ans) {
    return ans.substring(0,pos) + str + ans.substring(pos);
}

思路2

/**
 * @param {number} numerator
 * @param {number} denominator
 * @return {string}
 */
var fractionToDecimal = function(numerator, denominator) {
  // 首先,对特殊情况进行处理
  if (denominator == 0) return "";   // 分母,分子为0
  if (numerator == 0) return "0";

  let rst = [];
  if ((denominator > 0) ^ (numerator > 0)) rst.push("-"); // 商为负的情况
  let denom = Math.abs(denominator); // 分子,分母化为整数
  let numer = Math.abs(numerator);

  // 然后,模仿除法手算过程,每次得到的商存起来(数组),余数和下一个商是对应的,所以将余数作为键存到map中,对应的值为下一个商在数组中的序号。新得到的余数*10,作为下个被除数,当新得到得余数已存在map中时,在该存在的余数对应的数组编号处插入前括号。
  let quotient = Math.floor(numer / denom);  
  rst.push(quotient);
  let remainder = numer % denom;
  if (!remainder) return rst.join("");
  rst.push(".");  // 插入小数点
  let remMap = new Map();

  while (remainder && !remMap.has(remainder)) { // 小数部分
      remMap.set(remainder, rst.length);
      remainder *= 10;
      rst.push(Math.floor(remainder / denom));
      remainder %= denom;
  }

  if (remMap.has(remainder)) {
        rst.push(")");
        let index = remMap.get(remainder);
        rst.splice(index, 0, "(");
  }
  return rst.join("");
};