leetcode-150

150. 逆波兰表达式求值

根据 逆波兰表示法,求表达式的值。

有效的算符包括 +-*/ 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。

说明:

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

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
输入:tokens = ["2","1","+","3","*"]
输出:9
解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9

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

输入: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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution:
def evalRPN(self, tokens) -> int:
operator = ["+","-","*","/"]
# res = 0
stack = list()

for i in range(len(tokens)):
ch = tokens[i]
if ch in operator:
operator1 = int(stack.pop()) #
operator2 = int(stack.pop())
if ch == "+":
cur_res = operator2 + operator1
elif ch == "-":
cur_res = operator2 - operator1
elif ch =="*":
cur_res = operator2 * operator1
elif ch == "/":
cur_res = int(operator2 / operator1)
stack.append(cur_res)
res = cur_res

else:
stack.append(tokens[i]) # 添加操作数
# print(stack)
return int(stack[0])

解法二(官方题解):数组模拟栈

如果使用数组代替栈,则需要预先定义数组的长度。

对于长度为 $n$ 的逆波兰表达式,显然栈内元素个数不会超过 $n$,但是将数组的长度定义为 $n$ 仍然超过了栈内元素个数的上界。

那么,栈内元素最多可能有多少个?

对于一个有效的逆波兰表达式,其长度 $n$ 一定是奇数,且操作数的个数一定比运算符的个数多 $1$ 个,即包含$\frac { n + 1 } { 2 }$个操作数和$\frac { n - 1 } { 2 }$个运算符。

考虑遇到操作数和运算符时,栈内元素个数分别会如何变化:

  • 如果遇到操作数,则将操作数入栈,因此栈内元素增加 11 个;
  • 如果遇到运算符,则将两个操作数出栈,然后将一个新操作数入栈,因此栈内元素先减少$2$个再增加 $1$ 个,结果是栈内元素减少 $1$ 个。

由此可以得到操作数和运算符与栈内元素个数变化的关系:遇到操作数时,栈内元素增加 $1$ 个;遇到运算符时,栈内元素减少 $1$ 个。

最坏情况下,$\frac{n+1}{2}$个操作数都在表达式前面,$\frac{n-1}{2}$个运算都在表达式的后面,此时栈内元素最多为$\frac{n+1}{2}$个。

在其余情况下,栈内元素总是少于$\frac{n+1}{2}$个。因此在任何情况下,栈内元素最多可能有$\frac{n+1}{2}$个,因此将数组长度定义为$\frac{n+1}{2}$即可。

具体实现方面,创建数组 $stack$ 模拟栈,数组下标 0 的位置对应栈底,定义 $index$ 表示栈顶元素的下标位置,初始时栈为空,$index=−1$。当遇到操作数和运算符时,进行如下操作:

  • 如果遇到操作数,则将$index$ 的值加 1,然后将操作数赋给$stack[index]$;

  • 如果遇到运算符,则将$index$的值减1,此时$stack[index]$和$stack[index+1]$的元素分别是左操作数和右操作数,使用运算符对两个操作数进行运算,将运算得到的心操作数赋给 $stack[index]$

整个逆波兰表达式遍历完毕之后,栈内只有一个元素,因此 $index=0$,此时 $stack[index] $即为逆波兰表达式的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution:
def evalRPN(self, tokens: List[str]) -> int:
op_to_binary_fn = {
"+": add,
"-": sub,
"*": mul,
"/": lambda x, y: int(x / y), # 需要注意 python 中负数除法的表现与题目不一致
}

n = len(tokens)
stack = [0] * ((n + 1) // 2)
index = -1
for token in tokens:
try:
num = int(token)
index += 1
stack[index] = num
except ValueError:
index -= 1
stack[index] = op_to_binary_fn[token](stack[index], stack[index + 1])

return stack[0]
作者

bd160jbgm

发布于

2021-05-30

更新于

2021-05-30

许可协议