【leetcode】592.分数加减运算(python)

一、题目描述

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

输入: expression = “-1/2+1/2”
输出: “0/1”

示例2:

输入: expression = “-1/2+1/2+1/3”
输出: “1/3”

示例3:

输入: expression = “1/3-1/2”
输出: “-1/6”

提示:

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

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/fraction-addition-and-subtraction
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

二、解题思路

2.1 查找 ‘/’ 所在位置(第一思路)

在字符串中搜寻 ’/‘ 的所在位置,判断其前面的数字位数及符号,判断其后面的数字位数;
将分子分母分别放入到对应的列表中,分母列表连乘获得统一的分母形式,再将分子列表中对应的元素乘以对应的因子;
分子列表求和,将分子列表所求和与分母列表的连乘结果约分,最后再转化为字符串形式
代码如下:

class Solution:
    def fractionAddition(self, expression: str) -> str:
        numerator= [] 		# 分子
        denominator = []    # 分母
        ## 分别提取分子分母
        for idx, elem in enumerate(expression):
            if (elem == '/'):
                ## 收集分子
                if (idx-2 >= 0 and (expression[idx-2] not in ['+', '-'])): 
                    if (idx-3 >= 0 and expression[idx-3] == '-'):
                        numerator.append(-int(expression[idx-2] + expression[idx-1]))
                    else:
                        numerator.append(int(expression[idx-2] + expression[idx-1]))
                else:
                    if (idx-2 >= 0 and expression[idx-2] == '-'):
                        numerator.append(-int(expression[idx-1]))
                    else:
                        numerator.append(int(expression[idx-1]))
                
                ## 收集分母
                if (idx+2 < len(expression) and (expression[idx+2] not in ['+', '-'])):
                    denominator.append(int(expression[idx+1] + expression[idx+2]))
                else:
                    denominator.append(int(expression[idx+1]))

        ## 化为分母相同的形式 
        Com_factor = 1  # 分母的公倍数
        for i in range(len(denominator)):
            Com_factor *= denominator[i]       
        for j in range(len(numerator)):
            numerator[j] = numerator[j] * (Com_factor // denominator[j])

        ## 分子求和并与分母约分
        numerator_sum = sum(numerator)
        my_gcd = gcd(numerator_sum, Com_factor) # gcd:求最大公倍数
        my_str = str(numerator_sum // my_gcd) + '/' + str(Com_factor // my_gcd)
        return my_str

缺点:判断 ’/‘ 前后位置的数字位数或者符号时逻辑异常繁琐

2.2 利用python中分数表达Fraction函数

2.2.1 Fraction函数介绍

例:

from fractions import Fraction

x=Fraction(1,3)
y=Fraction(4,6)

print(x+y)				# 输出:Fraction(1, 1)
print(Fraction('.25'))	# 输出:Fraction(1, 4)
print(Fraction('1/4'))	# 输出:Fraction(1, 4)

print(x.numerator)		# 输出:1
print(x.denominator)	# 输出:3

2.2.2 解题

在字符串中搜寻 ‘+’ 和 ‘-’,找到后标记对应的op(符号标志)为相应的正或者负;
从上一个符号位置到当前符号位置中间的既为我们所需要的分数,利用Fraction提取后需要乘以上一次搜寻到的符号;
由于最后一个分数的后面没有符号,所以在结束搜寻符号的循环后不要忘记把最后一个分数计算到总的分数中;
代码如下:(参考思路:Leetcode用户@Azusa Tsang)

from fractions import Fraction

class Solution:
    def fractionAddition(self, expression: str) -> str:
        my_str = 0
        if (expression[0] == '-'):
            start = 1
            op = -1
        else:
            start = 0
            op = 1

        for i in range(start, len(expression)):
            if (expression[i] == '+'):
                my_str += op * Fraction(expression[start: i])
                op = 1
                start = i + 1
            elif (expression[i] == '-'):
                my_str += op * Fraction(expression[start: i])
                op = -1
                start = i + 1
            else:
                pass
        
        my_str += op * Fraction(expression[start:])
        return f'{my_str.numerator}/{my_str.denominator}'
        # f用法:f'{x1}...{x2}...'   
        # 其中x1、x2代表变量,...代表任意字符串

相较于思路一,实现过程更加清晰易懂

2.3 类似递归的思路(来自力扣官网)

对于两个分数 x 1 y 1 \frac{x_1}{y_1} y1x1 x 2 y 2 \frac{x_2}{y_2} y2x2,它们的相加结果为:
x 1 × y 2 + x 2 × y 1 y 1 × y 2 \frac{x_1 \times y_2 + x_2 \times y_1}{y_1 \times y_2} y1×y2x1×y2+x2×y1
令初始的分子分母分别为:numerator = 0,denominator = 1,而每次新取出的分子分母分别为:numerator_i,denominator_i,则由上述公式可以得到:
{ n u m e r a t o r = n u m e r a t o r ∗ d e n o m i n a t o r i + n u m e r a t o r i ∗ d e n o m i n a t o r d e n o m i n a t o r = d e n o m i n a t o r ∗ d e n o m i n a t o r i \begin{cases} & numerator = numerator * denominator_i + numerator_i * denominator\\ & denominator = denominator * denominator_i \end{cases} {numerator=numeratordenominatori+numeratoridenominatordenominator=denominatordenominatori
作者:LeetCode-Solution
链接:https://leetcode.cn/problems/fraction-addition-and-subtraction/solution/fen-shu-jia-jian-yun-suan-by-leetcode-so-2mto/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

搜寻字符串中的每一位,若为数字,则将该一位或两位的数字按位读到 numerator_i 中,跳过 ‘/’ 所在的位置后,继续读取一位或两位的数字按位读到 denominator_i 中;
执行上述公式,更新 numerator 和 denominator 后, 再次进入字符串继续进行搜寻下一个分数;
去最后的分子分母最大公倍数,返回约分后的字符串

class Solution:
    def fractionAddition(self, expression: str) -> str:
        numerator = 0   # 分子
        denominator = 1 # 分母
        n = len(expression)
        i = 0
        while (i < n):
            numerator_i = 0
            denominator_i = 0
            op = 1
            if (expression[i] == '-' or expression[i] == '+'):
                if (expression[i] == '-'):
                    op = -1
                i += 1

            ## 读取分子
            while (i < n and expression[i].isdigit()):
                numerator_i = numerator_i * 10 + op * int(expression[i])
                i += 1
            
            i += 1 		# '/'位置,跳过

			## 读取分母
            while (i < n and expression[i].isdigit()):
                denominator_i = denominator_i * 10 + int(expression[i])
                i += 1
            
            numerator = numerator*denominator_i + numerator_i*denominator
            denominator = denominator * denominator_i

        com_factor = gcd(abs(numerator), denominator)
        return f'{numerator//com_factor}/{denominator//com_factor}'

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值