天天看点

Leetcode 剑指 Offer II 036. 后缀表达式

作者:每日精选算法题
题目难度: 中等
原题链接[1]
今天继续更新 Leetcode 的剑指 Offer(专项突击版)系列, 大家在公众号 算法精选 里回复 剑指offer2 就能看到该系列当前连载的所有文章了, 记得关注哦~

题目描述

  • 根据 逆波兰表示法,求该后缀表达式的计算结果。
  • 有效的算符包括 +、-、*、/ 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。

说明:

  • 整数除法只保留整数部分。
  • 给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。

示例 1:

  • 输入:tokens = ["2","1","+","3","*"]
  • 输出:9
  • 解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9

示例 2:

  • 输入:tokens = ["4","13","5","/","+"]
  • 输出:6
  • 解释:该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6

示例 3:

  • 输入:tokens = ["10","6","9","3","+","-11","","/","","17","+","5","+"]
  • 输出:22
  • 解释:
  • 该算式转化为常见的中缀算术表达式为:
((10 * (6 / ((9 + 3) * -11))) + 17) + 5
= ((10 * (6 / (12 * -11))) + 17) + 5
= ((10 * (6 / -132)) + 17) + 5
= ((10 * 0) + 17) + 5
= (0 + 17) + 5
= 17 + 5
= 22
           

提示:

  • 1 <= tokens.length <= 10^4
  • tokens[i] 要么是一个算符("+"、"-"、"*" 或 "/"),要么是一个在范围 [-200, 200] 内的整数
  • 逆波兰表达式: 逆波兰表达式是一种后缀表达式,所谓后缀就是指算符写在后面。平常使用的算式则是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 ) 。该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * ) 。
  • 逆波兰表达式主要有以下两个优点: 去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中。

题目思考

  1. 如何模拟整个计算过程?

解决方案

思路

  • 分析题目, 正如提示中所说的, 我们可以采用栈来解决这个问题:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中。
  • 具体实现方面, 我们可以维护一个操作符映射字典, 它的 key 是对应符号, value 是具体的操作, 这里直接使用 Python3 的 lambda 表达式
  • 然后遍历每个 token, 判断其是否是操作符: 是的话, 就利用映射字典得到具体的 lambda 操作, 然后依次弹出栈顶两个数字进行计算, 并将结果压入栈中否则就将其转成 int 压入栈中
  • 由于题目保证给定的表达式一定有效, 那么最终栈中一定只存在一个数字, 就是最终结果, 直接将其返回即可
  • 下面的代码就对应了上面的整个过程, 并且有详细的注释, 方便大家理解

复杂度

  • 时间复杂度 O(N): 只需要遍历所有 token 一遍
  • 空间复杂度 O(N): 栈最多存 N 个元素

代码

class Solution:
    def evalRPN(self, tokens: List[str]) -> int:
        # 操作符映射字典: {符号:lambda操作}
        operators = {
            "+": lambda a, b: a + b,
            "-": lambda a, b: a - b,
            "*": lambda a, b: a * b,
            "/": lambda a, b: int(a / b),
        }
        # 数字栈
        numStack = []
        for token in tokens:
            if token in operators:
                # 当前token是操作符, 提取其对应操作
                op = operators[token]
                # 然后弹出栈顶的两个操作数, 栈顶是b, 下面一个是a
                b, a = numStack.pop(), numStack.pop()
                # 然后将计算得到的新数字重新压入栈中
                numStack.append(op(a, b))
            else:
                # 当前token是数字, 将其转换成int后压入栈中
                numStack.append(int(token))
        # 最终栈只存在一个元素, 即为最终结果
        return numStack.pop()
           

参考资料

[1]

原题链接: https://leetcode.cn/problems/8Zf90G