在问 · 算法题解

150. 逆波兰表达式求值

题目描述

输入字符串数组 tokens,它是一个用逆波兰表示法(后缀表达式)写成的算式。计算它的值,返回一个整数。

后缀表达式把运算符放在两个操作数后面,不需要括号。例如 (1 + 2) * (3 + 4) 写成 1 2 + 3 4 + *。从左往右扫描:遇到数字就压栈;遇到运算符就弹出两个数计算,再把结果压回去。先弹出的是右操作数。

运算符只有 +、-、*、/。整数除法的结果向零取整。输入保证是合法的表达式,不会出现除以 0,最终结果和中间结果都在 32 位整数范围内。

示例 1
输入:tokens = ["2","1","+","3","*"]
输出:9

解释:对应 (2 + 1) * 3 = 9。

示例 2
输入:tokens = ["4","13","5","/","+"]
输出:6

解释:对应 4 + 13 / 5,其中 13 / 5 取整为 2,结果 6。

示例 3
输入:tokens = ["10","6","9","3","+","-11","*","/","*","17","+","5","+"]
输出:22

解释:6 / -132 向零取整为 0,之后得到 0 + 17 + 5 = 22。

数据范围

  • 1 <= tokens.length <= 10^4
  • tokens[i] 是 +、-、*、/ 之一,或是 [-200, 200] 范围内的整数。

解题思路:栈

用栈。从左到右扫描:遇到数字就入栈;遇到运算符就弹出两个数,先弹出的是右操作数 b,再弹出的是左操作数 a,把 a op b 的结果压回栈。扫描结束后,栈里只剩一个数,就是答案。

为什么正确

栈中保存的是已经算好、但还没被后面运算符用掉的值,从栈底到栈顶按出现顺序排列。

复杂度分析

时间 O(n),空间 O(n)。

易错点

减法和除法不满足交换律,一定是“后弹出的 a”op“先弹出的 b”。除法要向零截断:Python 里 -7 // 2 = -4 是错的,要用 int(-7 / 2) = -3。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def evalRPN(self, tokens: List[str]) -> int:
        stack = []
        for t in tokens:
            if t in '+-*/':
                b = stack.pop()
                a = stack.pop()
                if t == '+':
                    stack.append(a + b)
                elif t == '-':
                    stack.append(a - b)
                elif t == '*':
                    stack.append(a * b)
                else:
                    stack.append(int(a / b))
            else:
                stack.append(int(t))
        return stack[0]

载入编辑器,自己跑一遍 →

其他解法

栈从前向后扫描,用显式栈保存操作数;递归从后向前解析,用系统调用栈代替显式栈;两者时间和空间都是 O(n)。

解法 2:从后向前递归 时间 O(n),空间 O(n)

逆波兰表达式的最后一个记号是整棵表达式树的根。用指针 pos 从末尾向前读:读到数字就直接返回;读到运算符,就先递归求出右操作数,再递归求出左操作数,最后计算结果。除法向零截断。

把表达式看成树来求值,体现后缀表达式和表达式树的对应关系。递归深度可能达到 n,需要注意调用栈上限。

import sys

class Solution:
    def evalRPN(self, tokens: List[str]) -> int:
        sys.setrecursionlimit(max(10000, 2 * len(tokens) + 100))
        self.pos = len(tokens) - 1

        def calc():
            t = tokens[self.pos]
            self.pos -= 1
            if t not in '+-*/':
                return int(t)
            b = calc()
            a = calc()
            if t == '+':
                return a + b
            if t == '-':
                return a - b
            if t == '*':
                return a * b
            return int(a / b)

        return calc()

栈与堆 专题的其他题目

查看 栈与堆 全部题目 →