返回

让计算器为我们解忧:解构LeetCode 227 基本计算器 II

前端

算术表达式的计算
在日常生活中,我们经常会遇到各种各样的数学表达式,例如“2 + 3 * 4”或“(1 + 2) * (3 + 4)”。这些表达式通常由数字、运算符和括号组成,我们需要根据运算符的优先级和结合性来计算出表达式的值。

认识逆波兰表达式

逆波兰表达式(也称为后缀表达式)是一种特殊的数学表达式表示法,它将运算符放在操作数之后。例如,表达式“2 + 3 * 4”的逆波兰表达式为“2 3 4 * +”。

栈的应用

栈是一种先进后出(LIFO)的数据结构,它可以用来存储运算数和运算符。在计算逆波兰表达式时,我们可以使用栈来存储运算数和运算符,并根据运算符的优先级和结合性来计算出表达式的值。

运算符优先级

运算符优先级是指运算符的计算顺序。在逆波兰表达式中,运算符的优先级决定了运算的顺序。例如,乘法和除法的优先级高于加法和减法,因此“2 + 3 * 4”的计算顺序为先计算“3 * 4”,然后再计算“2 + 12”。

代码实现

def calculate(s):
  # 将表达式转换为逆波兰表达式
  rpn = to_rpn(s)

  # 创建栈
  stack = []

  # 遍历逆波兰表达式
  for token in rpn:
    # 如果是数字,则入栈
    if token.isdigit():
      stack.append(int(token))
    # 如果是运算符,则从栈中弹出两个操作数,进行运算,并将结果入栈
    else:
      operand2 = stack.pop()
      operand1 = stack.pop()
      result = eval(str(operand1) + token + str(operand2))
      stack.append(result)

  # 返回栈顶元素,即表达式的值
  return stack[-1]

def to_rpn(s):
  # 创建运算符栈
  op_stack = []

  # 创建输出队列
  output = []

  # 遍历表达式
  for token in s:
    # 如果是数字,则直接加入输出队列
    if token.isdigit():
      output.append(token)
    # 如果是左括号,则入栈
    elif token == '(':
      op_stack.append(token)
    # 如果是右括号,则将栈顶运算符弹出并加入输出队列,直到遇到左括号
    elif token == ')':
      while op_stack[-1] != '(':
        output.append(op_stack.pop())
      op_stack.pop()  # 弹出左括号
    # 如果是运算符,则将栈顶运算符弹出并加入输出队列,直到遇到优先级较低的运算符或左括号
    else:
      while op_stack and precedence(token) <= precedence(op_stack[-1]):
        output.append(op_stack.pop())
      op_stack.append(token)

  # 将栈中剩余的运算符加入输出队列
  while op_stack:
    output.append(op_stack.pop())

  # 返回逆波兰表达式
  return output

# 运算符优先级
def precedence(op):
  if op == '+' or op == '-':
    return 1
  elif op == '*' or op == '/':
    return 2
  else:
    return 0

结语

逆波兰表达式和栈为我们提供了一种简洁而强大的方法来计算复杂的数学表达式。通过将表达式转换为逆波兰表达式并使用栈来存储运算数和运算符,我们可以轻松地计算出表达式的值。

希望这篇文章对您有所帮助!如果您有任何疑问或建议,请随时给我留言。