ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

592. 分数加减运算

2022-07-28 00:05:11  阅读:164  来源: 互联网

标签:分数 pre 592 加减 num let now 分母


题目描述:

  给定一个表示分数加减运算的字符串 expression ,你需要返回一个字符串形式的计算结果。 这个结果应该是 不可约分 的分数,即最简分数。 如果最终结果是一个整数,例如 2,你需要将它转换成分数形式,其分母为 1,所以 2 应该被转换为 2/1。

提示:

  • 输入和输出字符串只包含 '0' 到 '9' 的数字,以及 '/', '+' 和 '-'。 
  • 输入和输出分数格式均为 ±分子/分母。如果输入的第一个分数或者输出的分数是正数,则 '+' 会被省略掉。
  • 输入只包含合法的最简分数,每个分数的分子与分母的范围是  [1,10]。 如果分母是1,意味着这个分数实际上是一个整数。
  • 输入的分数个数范围是 [1,10]。
  • 最终结果的分子与分母保证是 32 位整数范围内的有效整数。

 

示例:
输入:expression = "-5/2+10/3+7/9"
输出:"29/18"

 

解题思路:

  我没有采用将所有分母一起通分的方法,因为考虑到如果分母很大的情况下,全部一起通分可能会溢出(实际上,对于该题的条件来说这样的考虑是多余的- -!)。我采取的做法是,每次将相邻两个分母通分,然后计算相应的分子,最后对分子分母进行约分,计算结果作为“前一个分数”。

  这里,我定义:

  • pre_mu:前一个分数的分母
  • pre_zi:前一个分数的分子
  • pre_sym:前一个分数的正负号(-1或1)
  • now_mu:当前分数的分母
  • now_zi:当前分数的分子
  • now_sym:当前分数的正负号

  注意,我的代码逻辑中,每次处理“前一个分数与当前分数相加减的计算结果”的时机是遍历到下一个分数的正负号时,计算完毕后将计算结果作为“前一个分数”。如示例中,循环走到“+10/3”的‘+’时,代码才开始处理前一个分数“0/1”(初始值)与当前分数“-5/2”的计算结果,然后将结果“-5/2”作为“前一个分数”;然后继续提取“+10/3”各项值。当下一次走到“+7/9”的“+”时,才处理“-5/2”与“+10/3”的计算结果。

  num变量先以字符串的形式存储分子(有可能是一个数字,也可能是两个),当遍历到“/”符号时,才将字符串num的数字转换为数值,存储在now_zi中,并将num置空;然后num接着存储“/”后的数字,当遍历到下一个“-”或“+”号时,同样将字符串num转换为数值,作为分母存储在now_mu中,并进行相应的计算,计算出新的pre_mu、pre_zi与pre_sym。

步骤如下:

依次遍历expression中的字符,

  1. 当字符为'-'或‘+’时,先将字符串num转化为数字作为分母,然后计算前面两个分数的运算结果,将结果作为新的前一个分数;并且,保存当前分数的正负号;
  2. 当字符为数字时,将其添加在字符串num后面(应对分子或分母为10的情况);
  3. 若不满足上面两点,也即字符为'/'时,将字符串num转化为数字作为分子,同时初始化num = 0;
  4. 遍历完expression后,我们还未计算最后一个分数与前一个分数运算的值,需要多写一次操作。

 

代码实现:

/**
 * @param {string} expression
 * @return {string}
 */
var fractionAddition = function(expression) {

    //初始化,假设"前一个分数"为0/1,这不影响最后的计算结果
    let pre_zi = 0;
    let pre_mu = 1;
    let pre_sym = 1;

    let num = '';
    let now_zi = 0;
    let now_mu = 0;
    let now_sym = 1;
    for(let i=0;i<expression.length;i++){
        if(expression[i]==='-'||expression[i]==='+'){
            //若num为'',表示是第一个数,此时只有"前一个分数0/1",凑不齐两个分数,不作处理;
            //若num不为空,表示前面已经已经"前一个分数"与"当前分数",进行计算
            if(num){
                now_mu = parseInt(num);//提取当前分数的分母
                num = '';
                let new_mu = computedMu(pre_mu,now_mu);//计算两分母通分后的结果
                let new_zi = pre_sym*(new_mu/pre_mu)*pre_zi + now_sym*(new_mu/now_mu)*now_zi;//计算分子

                //分子分母约分前,先对分子进行处理
                if(new_zi<0){
                    pre_sym = -1;
                    new_zi = - new_zi;
                }else{
                    pre_sym = 1;
                }

                //使用辗转相除法计算出最大公约数
                let res = gcd(new_zi,new_mu);

                //若分子或分母存在零值(分母不可能为0),将"前一个分数置为0/1"
                if(res===0){
                    pre_zi = 0;
                    pre_mu = 1;
                }else{
                    //约分后的结果
                    pre_zi = new_zi/res;
                    pre_mu = new_mu/res;
                }
            }
            //别忘了保存遍历到的分数的正负号
            now_sym = expression[i]==='-'?-1:1;
            continue;
        }else if(parseInt(expression[i]).toString()!=='NaN'){//若遍历到的字符为数字,先添加到字符串num末尾
            num += expression[i];
            continue;
        }else{
            //当遍历到"/"符号时,提取出当前分数的分子
            now_zi = parseInt(num);
            num ='';
        }
    }

    //遍历结束后,别忘了我们每次处理"前一个分数与当前分数相加减的计算结果"的时机是遍历到下一个分数的正负号时,
    // 此时我们还未处理最后一个分数与前一个分数
    now_mu = parseInt(num);
    let new_mu = computedMu(pre_mu,now_mu);
    let new_zi = pre_sym*(new_mu/pre_mu)*pre_zi + now_sym*(new_mu/now_mu)*now_zi;
    if(new_zi<0){
        pre_sym = -1;
        new_zi = - new_zi;
    }else {
        pre_sym = 1;
    }
    let res = gcd(new_zi,new_mu);
    
    //若最大公约数为0,表示结果的分子存在零值,直接返回"0/1"
    if(res===0){
        return '0/1';
    }else{
        pre_zi = new_zi/res;
        pre_mu = new_mu/res;
    }
    let sym = pre_sym===-1?'-':'';
    return sym + pre_zi +'/'+pre_mu;
};

//计算两分母通分后的新分母,也即最大公倍数
function computedMu(n1,n2){
    let res = gcd(n1,n2);
    return (n1/res)*(n2/res)*res;
}

//求最大公约数
function gcd(n1,n2){
    if(n1===0||n2===0){
        return 0;
    }
    while(n2!==0){
        let res = n1 %n2;
        n1 = n2 ;
        n2 = res;
    }
    return n1;
}

 

标签:分数,pre,592,加减,num,let,now,分母
来源: https://www.cnblogs.com/evil-shark/p/16525784.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有