四则运算解析器| 豆包MarsCode AI刷题

137 阅读4分钟

实现一个简单四则运算解析器:从零开始解析表达式

题目背景:四则运算的挑战

最近在刷题时遇到了一道有趣的编程题——实现一个基本计算器。题目要求我们解析一个字符串形式的数学表达式并计算其结果。表达式包含加减乘除、括号以及数字,最终需要返回整数结果。此外,还明确要求不能借助内置的 eval 函数,而是从头实现解析逻辑。

题目要求

给定一个字符串 expression,如 "3+4*5/(3+2)",需要返回其计算结果。题目示例如下:

输入:expression = "3+4*5/(3+2)"
输出:7

问题分析

这道题的难点在于需要自己实现运算优先级的处理:

  1. 加减法乘除法优先级不同。
  2. 括号改变了优先级,需要优先计算括号内的表达式。
  3. 实现过程中需要正确解析字符串,并依次计算中间结果。

为了解决这些问题,我们需要分步构造计算器的逻辑。


解题思路:构造一个递归解析器

面对如此复杂的运算优先级,可以借助递归方法来逐层解析括号内容:

  1. 分层解析:外层负责处理加减法,遇到括号时递归调用内部表达式解析器。
  2. 局部计算:在同一级别中,先将乘除法优先处理,再处理加减法。
  3. 栈模拟计算过程:用栈存储中间结果,将高优先级的计算直接压入栈中。

以下是实现的核心步骤:

  1. 从左到右解析字符串,分割出数字和操作符。
  2. 当遇到括号时递归处理括号内部表达式。
  3. 将最终的中间结果合并,返回计算结果。

代码实现

以下是用 Python 实现的完整代码:

def calculate(expression: str) -> int:
    def helper(s: list) -> int:
        stack = []
        num = 0
        sign = '+'

        while len(s) > 0:
            char = s.pop(0)
            if char.isdigit():
                num = num * 10 + int(char)
            if char == '(':
                num = helper(s)
            if char in "+-*/)" or len(s) == 0:
                if sign == '+':
                    stack.append(num)
                elif sign == '-':
                    stack.append(-num)
                elif sign == '*':
                    stack.append(stack.pop() * num)
                elif sign == '/':
                    stack.append(int(stack.pop() / num))
                sign = char
                num = 0
                if char == ')':
                    break
        return sum(stack)

    return helper(list(expression))

测试与验证

用一些测试用例来验证代码是否正确:

# 示例 1
print(calculate("1+1"))  # 输出:2

# 示例 2
print(calculate("3+4*5/(3+2)"))  # 输出:7

# 示例 3
print(calculate("4*2*5-2/1"))  # 输出:12

# 示例 4
print(calculate("(1+(4+5+2)-3)+(6+8)"))  # 输出:23

# 示例 5
print(calculate("2*(5+5*2)/3+(6+8*3)"))  # 输出:40

通过测试可以发现,代码能正确解析表达式并返回期望的结果。


实现过程中的坑点与优化

  1. 整数除法处理:Python 的除法会返回浮点数,但题目要求返回整数,因此需要用 int() 强制转换。
  2. 多位数字解析:注意从字符串中连续读取多位数字,避免只解析个位。
  3. 括号嵌套问题:递归时需要正确处理多层括号的结束条件。

我的收获与心得

这道题让我充分理解了递归的强大之处。通过递归分层解析表达式,我们可以清晰地处理括号和优先级问题。用栈模拟计算过程,也让我对“分而治之”的思想有了更深刻的认识。

此外,借助这道题,我还学会了如何一步步将复杂问题拆解为可管理的小模块。每次完成一个小模块并验证正确性,能让整个程序的开发更加顺畅。


写在最后

如果你和我一样,是个后端开发者,可能觉得“计算器”这类题和日常业务需求关系不大。但通过这样的题目,我们可以锻炼对算法和数据结构的掌握程度,同时也能在复杂问题面前学会冷静分析、层层拆解。

有时候,刷题不仅是为了提升编程技能,更是一次提升逻辑思维的机会。如果你也对这道题感兴趣,不妨尝试一下!