简单四则运算题解 | 豆包MarsCode AI 刷题

85 阅读4分钟

简单四则运算题解

在数学计算时,我们会使用将括号从内向外展开的方式,逐步将表达式展开为没有括号的表达式,最后得出结果。

观察这个题目的输入和输出,他要求输入一个表达式,输出一个算术结果。而如果我们在展开所有括号前,每次计算都是计算括号内的表达式,并用括号内的运算结果替换掉原括号内的内容,我们发现计算括号内的表达式使用的算法以及输入输出居然和原本的函数一致,我们决定用递归的算法完成这道题目。

def solution(expression: str) -> int:
    pass

由于使用了递归,我们要在同一个函数中讨论多种不同的输入情况。在本题约束条件下的输入分为两种:

  1. 无括号的表达式
  2. 有括号的表达式

按照之前我们的想法,我们会使用递归将所有有括号的表达式处理为没有括号的表达式,因此第1种输入的情况下,算法会更复杂些,我们首先讨论第2种输入。

有括号的表达式

对于有括号的表达式,我们需要将式子里所有的括号内的表达式依次计算出,并替代掉原本括号的位置。在所有的括号都被替代后,表达式也将变为无括号的表达式。

def solution(expression):
    if '(' in expression:
        left = expression.find('(')
        right = match_kuohao(expression)
        return solution(expression[:left]+str(solution(expression[left+1:right]))+expression[right+1:])

为了简化代码逻辑,此处我也决定使用递归处理含括号的表达式,即每次递归只计算一次最左侧的括号内的表达式。

def match_kuohao(expression):
    left = expression.find('(')
    time = 0
    for i in range(left, len(expression)):
        if expression[i] == '(':
            time += 1
        if expression[i] == ')':
            time -= 1
        if time == 0:
            return i

由于括号内可能嵌套很多层的括号,如果直接使用pythonfind函数找到的不一定是与最左侧的左括号相互对应的右括号。我决定从使用一个计数器来记录当前位置的括号的嵌套层数,从左括号的位置开始,从左往右遍历寻找右括号的位置,遇到(就加一,遇到)就减去一。因此当计数器归零时,表示计数器找到了对应的右括号了。

无括号的表达式

计算无括号的表达式相对复杂些。但是由于没有了括号,我们需要考虑加减乘除的四则运算。我们此时仍可以使用递归的方法,先将所有的乘除法计算完再计算加减法。

为此,我们同样使用递归来完成,当表达式中存在乘除时,我们优先计算乘除,在所有乘除全部计算完成之后才计算加减法。由于此时没有括号,可以按照从左到右的顺序分别计算乘除法和加减法。

def match_kuohao(expression):
    if '(' in expression:
        # 有括号的情况,已经考虑过了
        pass
    elif '*' in expresssion or '/' in expression:
        # 找到最左侧的乘除法的位置,并决定使用哪个作为运算符,比较简单,忽略不写
        cheng_index = ...
        chu_index = ...
        operation = ...
        operation_index = ...

        # 找到左右操作数,比较简单,忽略不写
        left = ...
        left_index = ...
        right = ...
        right_index = ...
        if operation == '*':
            calculate = left * right
        else:
            calculate = int(left/right)
        return solution(expression[:left_index] + str(calculate) + expression[right_index+1:])
    else:
        # 加减法的情况,和乘除法比较类似,也忽略不写
        pass

此外,之前拆除所有括号时,所有负数的括号也全部被拆掉了,因此我们也需要将这些符号的正负属性转换到我们计算的+-*/符号里去,例如+(-5)被拆除括号,成为了+-5,此时我们将+变为-,将+-5变为-5即可。而倘若是*/,我们则统计乘除法左右操作数的负号数量,然后转换到左操作数前面即可,比如-2*-3的有2个负号,我们转换为2*3即可。

至此,我们的全部代码都已经完成。