224.基本计算器
难度 困难
题目
给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。
示例1
输入:s = “1 + 1”
输出:2
示例2
输入:s = " 2-1 + 2 "
输出:3
示例3
输入:s = “(1+(4+5+2)-3)+(6+8)”
输出:23
提示
- 1 <= s.length <= 3 * 105
- s 由数字、’+’、’-’、’(’、’)’、和 ’ ’ 组成
- s 表示一个有效的表达式
解题思路—双栈
遇到计算器问题就用两个栈来解决问题,一个数字栈(用来存数字),一个运算符栈(用来存运算符),同时,要定义运算符优先级。然后遍历字符串,分情况讨论:
- 遇到数字就直接存入数字栈(这其中还要对大于10的数进行处理)
- 对于遇到括号:
- 遇到左括号就直接存入运算符栈
- 遇到右括号就取出数字栈顶两个数,取出运算符栈顶一个运算符进行计算,直到遇到左括号为止,计算完到最后记得删除左括号
- 遇到非括号的一般运算符,则要比较当前运算符与上一个运算符的优先级,只有上一个运算符的优先级大于当前运算符的优先级时,才进行计算(对上一个运算符和栈顶两个数进行计算,计算完后将计算结果存入数字栈,再将当前运算符存入运算符栈)。否则,直接将当前运算符存入运算符栈
举个🌰 :
‘2+3*6-1’,应该先计算 3 * 6,再计算2 + 18 - 1。我们按照解题思路将‘2’存入数字栈,将‘+’存入运算符栈,接下来‘3’存入数字栈,则此时 num_stack:[2 3],op_stack:[+]。接下来遇到了‘*’,其上一个运算符为‘+’,上一个运算符优先级小于当前运算符优先级,则直接将‘*’入栈。不然要是进行计算的话,则就先计算2+3了,这样就错了。然后接下来‘6’入数字栈, num_stack:[2 3 6],op_stack:[+ *],接下来遇到‘-’,因为上一个运算符‘*’优先级大于当前运算符‘-’优先级,故进行计算,取出栈顶运算符‘*’和栈顶两个数‘6’和‘3’,计算6*3,并将计算结果18存入数字栈,再将‘-’存入运算符栈,则此时 num_stack:[2 18],op_stack:[+ -],接下来‘1’存入数字栈。哎,等等等等,大家有没有发现一个问题,将字符串最后一个元素‘1’存入数字栈后,字符串遍历结束,但是数字栈和运算符栈中还有元素没有计算,我们最后的结果肯定返回的是数字栈中的唯一剩下的一个数(最终计算结果),但是此刻,数字栈中还有[2 18 1],字符串遍历结束,程序到此终止了。所以为了将所有的数都计算完成,我们在程序开始就对字符串s两边加上括号,这样字符串最后一个元素必为右括号,遇到右括号就会对数字栈中元素进行计算,直到遇到左括号。
代码
class Solution(object):
def calculate(self, s):
"""
:type s: str
:rtype: int
"""
op_priority = {'+':0, '-':0, '*':1, '/':1, '%':1, '^':2}
# s一定要两边再加括号,这样才能计算完全,否则最后没有右括号还会少一部分没算
s = '(' + s.replace(' ', '').replace('(-', '(0-') + ')'
n = len(s)
i = 0
num_stack, op_stack = [], []
while i < n:
c = s[i]
i += 1
if c.isdigit():
num = int(c)
while i < n and s[i].isdigit():
# 防止有大于10的两位数字,即数字与数字之间没有运算符,则是一个大于10的整数
num = num * 10 + int(s[i])
i += 1
num_stack.append(num)
elif c == '(':
# 遇到左括号直接进运算符栈
op_stack.append(c)
elif c == ')':
# 遇到右括号则要进行计算,直到遇到左括号结束(对括号内数字运算)
while op_stack and op_stack[-1] != '(':
self.calc(num_stack, op_stack)
op_stack.pop() # 括号内数字计算完成,要删除左括号
else:
# 普通运算符要进行优先级比较,当上一个运算符优先级大于当前运算符时,才进行计算(对上一个运算符计算),然后再将当前运算符加入栈;反之,直接将当前运算符加入栈即可
while op_stack and op_stack[-1] != '(':
pre_op = op_stack[-1]
if op_priority[pre_op] < op_priority[c]:
break
else:
self.calc(num_stack, op_stack)
op_stack.append(c)
return num_stack[0]
def calc(self, num_stack, op_stack):
op, y, x = op_stack.pop(), num_stack.pop(), num_stack.pop() if num_stack else 0
re = 0
if op == '+':
re = x + y
if op == '-':
re = x - y
if op == '*':
re = x * y
if op == '/':
re = x / y
if op == '%':
re = x % y
if op == '^':
re = pow(x, y)
num_stack.append(int(re))
至此,此题解答完毕