AI刷题中档题 简单四则运算解析器 解答 | 豆包MarsCode AI刷题

45 阅读5分钟

简单四则运算解析器

问题描述

小F需要编写一个程序来计算给定的字符串表达式的值。表达式有效且可能包含以下元素:

  • 数字(0-9)
  • 运算符:加(+)、减(-)、乘(*)、除(/)
  • 括号:左括号 ( 和右括号 )

在计算时需注意以下规则:

  1. 无空格处理: 输入的表达式中不包含空格。

  2. 整数除法: 对于除法操作,结果需要取整(向零取整)。

  3. 优先级处理:

    • 乘法和除法优先于加法和减法。
    • 括号的优先级最高,括号内的表达式需要先计算。

目标是通过实现一个自定义的解析器计算表达式的值,不得使用内置的 eval 函数


分析问题与难点

  1. 操作符优先级:
    乘法和除法的优先级高于加法和减法。这意味着我们需要按照运算优先级的规则正确处理不同操作符。
  2. 括号嵌套:
    括号表示优先级最高,嵌套括号需要递归求解。每遇到一对括号时,需要单独计算括号内部的表达式。
  3. 字符串解析:
    需要逐字符解析字符串并将数字、运算符和括号分开处理,同时管理一个栈来帮助进行运算。
  4. 整数运算:
    除法的结果需要向零取整。例如,对于表达式 7 / 3,结果应该是 2 而不是 2.333

算法思路

为了解决上述问题,我们需要设计一个解析器,遵循以下步骤:

  1. 定义支持的操作符和数据结构

    • 使用一个栈(stack)来存储临时结果和中间运算符的优先级信息。
    • 将加减法的操作符视为低优先级,乘法和除法为高优先级。
  2. 逐字符扫描表达式

    • 如果是数字:将连续数字解析为整数。
    • 如果是加减法运算符:将当前的结果压入栈并记录运算符。
    • 如果是乘法或除法:从栈中取出上一个操作数,与当前操作数进行计算,并将结果重新压入栈。
    • 如果是左括号:递归调用,计算括号内的结果。
    • 如果是右括号:结束当前括号的递归处理。
  3. 栈中求和

    • 当所有字符处理完成时,栈中的所有元素代表一个加减法链表。直接求和即可得出结果。

代码实现

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

from collections import deque
from collections import Counter

def solution(s: str) -> int:

        strings = ["+","-","*","/"]
        n = len(s)
        res = 0
        pre = "+"
        stack = []
        i = 0
        while i < n:
            if s[i] != " " and s[i] in [str(i) for i in range(10)]:
                res = res*10 + ord(s[i]) - ord('0')

            if i == n-1 or s[i] in strings:
                if pre == "+":
                    stack.append(res)
                elif pre == "-":
                    stack.append(-res)
                elif pre == "*":
                    stack.append(stack.pop()*res)
                else:
                    stack.append(int(stack.pop()/res))
                res = 0
                pre = s[i]

            if s[i] == "(":
                balance = 1
                j = i+1
                while j < n:
                    if s[j] == '(':
                        balance+=1
                    elif s[j] == ')':
                        balance -= 1
                    if balance == 0:
                        break
                    j += 1
                res = solution(s[i+1:j])
                i = j
                if i == n-1:
                    if pre == "+":
                        stack.append(res)
                    elif pre == "-":
                        stack.append(-res)
                    elif pre == "*":
                        stack.append(stack.pop()*res)
                    else:
                        stack.append(int(stack.pop()/res))
            i += 1

        return sum(stack)



if __name__ == "__main__":
    #  You can add more test cases here
    print(solution("1+1") == 2)
    print(solution("3+4*5/(3+2)") == 7)
    print(solution("4+2*5-2/1") == 12)
    print(solution("(1+(4+5+2)-3)+(6+8)") == 23)
    
    

测试样例解析

样例1:
输入:"1+1"

  • 无括号、无优先级,直接计算 1+1=21+1=21+1=2。
    输出:2

样例2:
输入:"3+4*5/(3+2)"

  • 按优先级计算:

    • 4∗5=204*5=204∗5=20
    • 20/(3+2)=420/(3+2)=420/(3+2)=4
    • 3+4=73+4=73+4=7。
      输出:7

样例3:
输入:"4+2*5-2/1"

  • 按优先级计算:

    • 2∗5=102*5=102∗5=10
    • 2/1=22/1=22/1=2
    • 4+10−2=124+10-2=124+10−2=12。
      输出:12

样例4:
输入:"(1+(4+5+2)-3)+(6+8)"

  • 递归计算括号内的表达式:

    • (4+5+2)=11(4+5+2)=11(4+5+2)=11
    • 1+11−3=91+11-3=91+11−3=9
    • (6+8)=14(6+8)=14(6+8)=14
    • 9+14=239+14=239+14=23。
      输出:23

样例5:
输入:"2*(5+5*2)/3+(6+8*3)"

  • 递归计算括号内的表达式并遵循优先级:

    • (5+5∗2)=15(5+5*2)=15(5+5∗2)=15
    • 2∗15=302*15=302∗15=30
    • 30/3=1030/3=1030/3=10
    • (6+8∗3)=30(6+8*3)=30(6+8∗3)=30
    • 10+30=4010+30=4010+30=40。
      输出:40

复杂度分析

  1. 时间复杂度:

    • 表达式中的每个字符会被扫描一次,递归计算括号内部时可能重新扫描部分字符,复杂度为 O(n),其中 n 是表达式的长度。
  2. 空间复杂度:

    • 递归栈的深度与括号的嵌套层数有关,栈的空间复杂度为 O(d),其中 d 是括号的最大嵌套深度。

总结

该算法充分利用栈和递归机制,完成了一个基本计算器的实现,能够正确解析和计算复杂的嵌套表达式。在面试场景或工程中,该算法展示了对优先级、括号处理及整数除法等关键问题的细致考虑,是一个高效且易于扩展的实现方式