Java教程

592. 分数加减运算

本文主要是介绍592. 分数加减运算,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

题目描述:

  给定一个表示分数加减运算的字符串 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;
}

 

这篇关于592. 分数加减运算的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!