592. 分数加减运算
解题过程
INFO
题目链接 给定一个表示分数加减运算的字符串 expression ,你需要返回一个字符串形式的计算结果。 这个结果应该是不可约分的分数,即最简分数。 如果最终结果是一个整数,例如 2,你需要将它转换成分数形式,其分母为 1。所以在上述例子中, 2 应该被转换为 2/1
javascript
/**
* @link https://leetcode.cn/problems/fraction-addition-and-subtraction/
* @title 592. 分数加减运算
* @description 给定一个表示分数加减运算的字符串 expression ,你需要返回一个字符串形式的计算结果。
这个结果应该是不可约分的分数,即最简分数。 如果最终结果是一个整数,例如 2,你需要将它转换成分数形式,其分母为 1。所以在上述例子中, 2 应该被转换为 2/1
* @param {string} expression
* @return {string}
*/
// 解法一
// 思路:暴力解法,难点在最简公约数上
// 第一步:正则匹配到字符串对应分数元素数组(注意:负数分数需要带上符号)
// 第二步:循环遍历数组累加求和
// 第三步:判断是否是最简分数:判断基本的是否是最简分数、循环遍历分子或分母最小值递增判断是否是公约数
var fractionAddition = function (expression) {
const nums = expression.match(/-[\d/]+|\+?[\d/]+/g)
let total = nums[0]
for (let i = 1; i < nums.length; i++) {
const perArr = total.split('/')
const curArr = nums[i].split('/')
if (perArr[1] === curArr[1]) {
// 分母相同
total = (parseInt(perArr[0]) + parseInt(curArr[0])) + '/' + perArr[1]
} else {
// 分母不同
total = (parseInt(perArr[0]) * parseInt(curArr[1]) + parseInt(curArr[0]) * parseInt(perArr[1])) + '/' + (parseInt(perArr[1]) * parseInt(curArr[1]))
}
}
// 判断是否是最简分数
const [mole, deno] = total.split('/')
let lastMole = parseInt(mole)
let lastDeno = parseInt(deno)
if (![1, -1, 0].includes(parseInt(mole)) && parseInt(deno) !== 1) {
// 判断基本的是否是最简分数
const minNum = Math.min(Math.abs(parseInt(mole)), Math.abs(parseInt(deno)))
for (let i = 2; i <= minNum; i++) {
if (lastMole % i === 0 && lastDeno % i === 0) {
// 分子分母都能够整除则是公约数
lastMole = lastMole / i
lastDeno = lastDeno / i
// 降一是为了当前 i 在进行一次整除判断,防止有多次相同公约数
i = i - 1
continue
}
if (Math.abs(lastMole) < i || Math.abs(lastDeno) < i) {
// 循环除数最大值不能大于分子或分母
break
}
}
}
// 判断分子是否为0,分子为0是因为分子求和为0,分母没有舍去,原来是整个值为0的
return lastMole === 0 ? lastMole + '/' + 1 : lastMole + '/' + lastDeno
}
// 解法二
// 思路:来自题解的解法,还算不错的,比我做的解法一简洁一点
// 优点:正则匹配写的比我的简单,我的写法有点冗余了,执行效果更好一点
var fractionAddition = function (expression) {
const arr = expression.match(/-?\d+\/\d+/g)
let lastMole = 0, lastDeno = 1
// 求分子、分母最大公倍数(注意:分子分母的计算逻辑)
const gcb = (mole, deno) => {
if (deno === 0) {
// 如果分母为零,则返回分子
return mole
} else if (mole % deno === 0) {
// 如果分母除以分子整除,则返回分母
return deno
} else {
// 否则,调换分子分母位置,且分母改为分母除以分子的余数
return gcb (deno, mole % deno)
}
}
for (let str of arr) {
let symbol = 1 // 符号位,用于分子计算的正负值判断
if (str[0] === '-') {
str = str.slice(1)
symbol = -1
}
let numArr = str.split('/')
let mole = parseInt(numArr[0]), deno = parseInt(numArr[1])
lastMole = lastMole * deno + lastDeno * mole * symbol
lastDeno = lastDeno * deno
const lastNum = gcb (lastDeno, Math.abs(lastMole))
lastMole /= lastNum
lastDeno /= lastNum
}
return lastMole + '/' + lastDeno
}
// const result = fractionAddition ('-1/2+1/2') // 0/1
// const result = fractionAddition ('1/3-1/2') // -1/6
const result = fractionAddition ('-1/2+1/2+1/3') // 1/3
// const result = fractionAddition ('5/3+1/3') // 2/1
// const result = fractionAddition ('7/3+5/2-3/10') // 68/15
console.log(result)
解题感受
当初做的时候,半个小时没做出来,因为时间关系太晚了就暂时放弃做了。其实还是一点难度的,难点在于最简公约数的计算上。自己用了穷举法做的,基本考虑所有的问题写出来的,就是有点冗余,代码量有点大,执行效果还可以。解法二比较好,解题思路清晰一点,特别是计算最大公倍数的时候很简洁,值得学习
优质题解
- https://leetcode.cn/problems/fraction-addition-and-subtraction/solution/fen-shu-jia-jian-yun-suan-by-leetcode-so-2mto/
- https://leetcode.cn/problems/fraction-addition-and-subtraction/solution/by-ac_oier-rmpy/
- https://leetcode.cn/problems/fraction-addition-and-subtraction/solution/dai-ma-jian-ji-yi-chong-huan-bu-cuo-de-j-3x4z/