题目:
给你一个字符串表达式 s
,请你实现一个基本计算器来计算并返回它的值。
注意:不允许使用任何将字符串作为数学表达式计算的内置函数,比如 eval()
。
题目示例:
示例 1:
输入:s = "1 + 1"
输出:2
示例 2:
输入:s = " 2-1 + 2 "
输出:3
示例 3:
输入:s = "(1+(4+5+2)-3)+(6+8)"
输出:23
第一种解法(也是官方题解的思路,仅能针对+-的情况)
代码
class Solution:
def calculate(self, s: str) -> int:
ops=[1]#1代表+,-1代表减,记录当前遍历操作正负性
sign=1 #当前遍历运算位
n=len(s)
result=0
num=0
i=0
while i<n:
if s[i]=='+':
sign=ops[-1] #遇到正,当前不变
i+=1
elif s[i]=='-':
sign=-ops[-1] #遇到负,取反
i+=1
elif s[i]=='(': #进入括号,sign填入ops,根据括号当前状态进行加减运算
ops.append(sign)
i+=1
elif s[i]==')': #出括号,当前状态位出
ops.pop()
i+=1
elif s[i]==' ':
i+=1
else:
num=0
while i<n and s[i].isdigit(): #判断数字位用到了ord函数
num=num*10+ord(s[i])-ord('0')
i+=1
result+=num*sign
return result
代码思路:
代码逻辑:
ops为数组,保存当前运算位置的状态
sign根据ops[-1]实时更新运算符进行运算
第二种解法
代码
from collections import deque
class Solution:
def calculate(self, s: str) -> int:
ops=[] #存储数字以外的
nums=[0] #存储字符串的数字
s=s.replace(' ','') #将空格去掉
i=0
n=len(s)
val=0
def cal(ops,nums): #运算
if len(nums)<2:
return
a=nums.pop()
b=nums.pop()
op=ops.pop()
number=a+b if op=='+' else b-a
nums.append(number)
while i<n:
content=s[i] #当前遍历值
if content=='(':
ops.append(content)
elif content==')': #把当前括号栈推空
while ops and ops[-1]!='(':
cal(ops,nums)
ops.pop()
else: #遇到数字及符号
if content.isdigit():
while i<n and s[i].isdigit():
val=val*10+int(s[i])
i+=1
i-=1
nums.append(val)
val=0
else:
if i>0 and s[i-1]=='(': #如果新栈没有数目,则加一个0,防止空运算
nums.append(0)
while ops and ops[-1]!='(':
cal(ops,nums)
ops.append(content)
i+=1
while ops:
cal(ops,nums)
return nums[-1]
代码思路:
利用双栈来进行运算,ops栈用来保存运算符以及括号
nums栈用来保存计算数目
加减乘除版本
代码
class solution():
def calute(self,s):
priority = {'+': 1, '-': 1, '/': 2, '*': 2}
ops=[]
nums=[0]
i=0
s=s.replace(' ','')
length = len(s)
def caluteop(a,b,op):#计算子函数
if op=='+':
return a+b
elif op=='-':
return b-a
elif op=='*':
return a*b
elif op=='/':
return b/a
def cal(ops,nums):#计算函数
if len(nums)<2:
return
a=nums.pop()
b=nums.pop()
op=ops.pop()
result=caluteop(a,b,op)
nums.append(result)
while i<length:#递推函数
content=s[i]
if content=='(': #左边界
ops.append('(')
elif content==')': #右边界
while ops and ops[-1]!='(':
cal(ops,nums)
ops.pop() #右边界出
else: #数字或者计算
if content.isdigit(): #有数字就写入
val=0
while i<length and s[i].isdigit():
val=val*10+int(s[i])
i+=1
nums.append(val)
i-=1
else:
while ops and (content=='/' or content=='*') and ops[-1]!='(' and priority[ops[-1]]==priority[content]:#乘除计算优先级高,当上一级为左边界或+-的时候不计算
cal(ops,nums)
if i>0 and s[i-1]=='(' and (content=="+" or content=='-'):
nums.append(0)
while ops and (content=="+" or content=='-') and ops[-1]!='(':
cal(ops,nums)
ops.append(content)
i+=1
while ops:
cal(ops,nums)
return nums[-1]
代码思路:
在第二种解法上进行的更新。多了一个优先级字典
如果运算多了乘除运算,其优先级比+,-高,在只有加减的情况下,只要ops不为空,且ops[-1]不为左括号,平级运算递推即可。
但是在有乘除运算后,我们在遇到乘除运算符号时不能再进行平级递推,需要判断ops[-1]是否也是跟乘除同级的运算,将乘除平级递推完。
利用双栈来进行运算,ops栈用来保存运算符以及括号
nums栈用来保存计算数目