其他分享
首页 > 其他分享> > 592. 分数加减运算

592. 分数加减运算

作者:互联网

题目描述:

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

提示:

 

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

 

解题思路:

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

  这里,我定义:

  注意,我的代码逻辑中,每次处理“前一个分数与当前分数相加减的计算结果”的时机是遍历到下一个分数的正负号时,计算完毕后将计算结果作为“前一个分数”。如示例中,循环走到“+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