150 逆波兰表达式求值
标签: 栈
题目
题目链接:150 逆波兰表达式求值
根据 逆波兰表示法,求表达式的值。
有效的运算符包括 +, -, *, / 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
说明:
整数除法只保留整数部分。
给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。
示例 1:
输入: ["2", "1", "+", "3", "*"]
输出: 9
解释: 该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9 示例 2:
输入: ["4", "13", "5", "/", "+"]
输出: 6
解释: 该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6 示例 3:
输入: ["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 + 2 ) * ( 3 + 4 ) 。
该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * ) 。
逆波兰表达式主要有以下两个优点:
去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。
适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中。
思路
-
由题意可以得到的思路:
-
当遇到运算符时,需要将运算符前 2 个数字与当前运算符进行计算,并生成一个中间结果
-
这个中间结果也是可参与计算的数字,因此,需将其保存下来
-
- 用栈的实现方式就是:
- 遇到运算符,弹出栈顶的两个元素,与当前运算符做运算。并将计算结果压入栈
- 遇到括号,由题意可知,有无括号不影响计算结果,可以直接
contiue
- 遇到数字,压入栈
-
🌰:
["10", "6", "9", "3", "+", "-11", "*", "/", "*", "17", "+", "5", "+"]
stack t computing []
['10']
10
是数字,直接入栈 ['10', '6']
6
同上 ['10', '6', '9']
9
同上 ['10', '6', '9', '3']
3
同上 ['10', '6', '12']
+
是运算符,计算 9 + 3 = 12
,将12
压入栈['10', '6', '12', '-11']
-11
是数字,直接入栈 ['10', '6', '-132']
*
是运算符,计算 12 * (-11) = -132
,将-132
压入栈['10', '0']
/
是运算符,计算 6 / (-132) = 0
,将0
压入栈['0']
*
是运算符,计算 10 * 0 = 0
,将0
压入栈['0', '17']
17
是数字,直接入栈 ['17']
+
是运算符,计算 0 + 17 = 17
,将17
压入栈['17', '5']
5
是数字,直接入栈 ['22']
+
是运算符,计算 17 + 5 = 22
,将22
压入栈
代码
class Solution:
def evalRPN(self, tokens: List[str]) -> int:
stack = []
op = {'+', '-', '*', '/'}
op2 = {'(', ')'}
res = 0
for t in tokens:
# 1. 遇到运算符
if t in op:
n1 = stack.pop()
n2 = stack.pop()
# 除法需要单独处理
if t == '/':
tmp = abs(int(n2) ) // abs(int(n1))
# 求出 n1 n2 的正负号,还要排除 0 对该步骤的影响
if int(n2) != 0 and int(n2) * -1 == abs(int(n2)):
tmp *= -1
if int(n1) != 0 and int(n1) * -1 == abs(int(n1)):
tmp *= -1
stack.append(str(tmp))
# 其他运算符可直接运算
else:
stack.append(str(eval(n2 + t + n1)))
# 2. 遇到括号,可以直接跳过左右括号
elif t in op2:
continue
# 3. 遇到数字,直接将数字字符压入栈
else:
stack.append(t)
# 防止最后的栈顶元素是个浮点数
return int(eval(stack.pop() + "// 1"))
分析
- 时间复杂度需要
O(n)
,需要一次完整的线性遍历。 - 空间复杂度需要
O(n)
,需要保存未参与计算的数字。
留下评论