1. 问题描述:
输入一个只包含加减乘除和括号的合法表达式,求表达式的值。其中除表示整除。
输入格式
输入一行,包含一个表达式。
输出格式
输出这个表达式的值。
样例输入
1-2+3*(4-5)
样例输出
-4
数据规模和约定
表达式长度不超过100,表达式运算合法且运算过程都在int内进行。
来源:http://lx.lanqiao.cn/problem.page?gpid=T419
2. 思路分析:
这是一道经典的栈的应用的题目,对于表达式求解的问题都是经典的套路,我们需要声明两个栈,因为使用的是python语言所以使用列表来充当栈的作用,声明的操作符栈为ops,数字栈为nums,分别用来存储遍历和计算过程中的操作符和数字。首先遍历待计算的表达式s,对于当前的s[i],若为空格那么continue,尝试下一个字符此时需要i += 1(i为当前遍历的表达式的位置),当s[i]为数字那么需要计算出表达式中连续的数字(表达式中运算的数字位数可能大于等于2),然后将得到的连续的十进制数字加入到数字栈nums中,s[i]为左括号那么直接进栈,s[i]为右括号那么当栈不为空并且操作符栈顶元素不是左括号那么需要计算当前匹配的括号中表达式的值,可以写一个方法eval来计算当前匹配的括号表达式的值,在计算完当前匹配的括号表达式的值之后需要将最终的计算结果存入到数字栈nums中并且需要弹出操作符栈中的左括号,当s[i]为操作符那么就需要根据当前操作符栈顶元素与当前遍历的s[i]的优先级关系决定是将当前的s[i]加入到操作符栈还是弹出操作符计算表达式的值,我们设置一下四个操作符对应的优先级,"+", "-"优先级为1,"*","/"优先级为2,这里可以使用字典(哈希表)来设置操作符的优先级,s[i]为操作符存在有两种情况,如果当前操作符栈顶元素的优先级大于等于当前的s[i]那么我们需要计算弹出操作符对应的表达式的值,可以使用一个循环来计算表达式的值直到操作符栈为空或者是操作符栈的栈顶元素优先级小于s[i]那么循环就结束了,最终将s[i]加入到操作符栈中。当遍历表达式s结束之后我们还需要判断操作符栈是否存在元素,如果存在元素那么需要计算剩余的操作符对应的表达式的值。最终数字栈中第一个元素就是我们要求解的表达式的结果。
3. 代码如下:
from typing import List
class Solution:
# 计算当前的操作符对应的表达式的值
def eval(self, ops: List[str], nums: List[int]):
b, a = nums.pop(), nums.pop()
c = ops.pop()
if c == "+":
nums.append(a + b)
elif c == "-":
nums.append(a - b)
elif c == "*":
nums.append(a * b)
else:
nums.append(a // b)
def calculate(self, s: str):
i, n = 0, len(s)
pr = {"+": 1, "-": 1, "*": 2, "/": 2}
ops, nums = list(), list()
while i < n:
if s[i] == " ":
i += 1
continue
elif s[i] == "(":
ops.append(s[i])
i += 1
elif s[i] == ")":
# 计算表达式的值
while ops and ops[-1] != "(":
self.eval(ops, nums)
# 弹出操作符的左括号
ops.pop()
i += 1
# 当前的字符是数字
elif s[i].isalnum():
t = 0
while i < n and s[i].isalnum():
t = t * 10 + int(s[i])
i += 1
nums.append(t)
else:
# s[i]为操作符且当前ops栈顶元素不为左括号判断栈顶操作符的与当前s[i]的优先级大小
while ops and ops[-1] != "(" and pr[ops[-1]] >= pr[s[i]]:
self.eval(ops, nums)
ops.append(s[i])
i += 1
# 计算剩余的操作符对应的表达式的值
while ops:
self.eval(ops, nums)
return nums[0]
if __name__ == '__main__':
# 从控制台输入表达式
print(Solution().calculate(input()))