题目分析
根据所给题目,可知问题是要求我们实现一个计算器来计算简单的字符串表达式。因为表达式中可以包含加、减、乘、除以及括号,所以我们需要根据运算优先级和括号来正确地计算结果。栈先进后出的特点就可以很好地处理括号、运算符和数字,故我们可以使用栈来帮助我们处理这个问题。
思路
-
使用两个栈:
ops栈用来保存运算符。nums栈用来保存数值。
-
遇到数字时,直接加入
nums栈 -
遇到运算符时,根据运算符的优先级来决定是否进行运算:
- 如果当前运算符优先级比栈顶运算符低,就先执行栈顶运算符的运算
-
遇到括号时,遇到左括号进入递归,遇到右括号时计算当前括号内的内容
解题步骤
1.数字的提取:需要通过遍历字符串来识别数字
2.运算符的处理:加法、减法、乘法和除法需要按照优先级来处理,乘除法的优先级高于加减法
3.括号的处理:当遇到括号时,可以递归地求解括号内的子表达式
4.整数除法:按照题意,除法应该返回整数结果,即执行整数除法
复杂度分析:
1.时间复杂度: O(n),其中n是表达式的长度。每个字符至多被处理一次,栈的操作(压入和弹出)也是O(1)的
2.空间复杂度: O(n),用于存储运算符和数字的栈
具体实现
def solution(expression):
def apply_operator(oper, b, a):
if oper == '+':
return a + b
elif oper == '-':
return a - b
elif oper == '*':
return a * b
elif oper == '/':
# 执行整数除法
return a // b if a * b >= 0 else -(abs(a) // abs(b))
def precedence(op):
if op == '+' or op == '-':
return 1
if op == '*' or op == '/':
return 2
return 0
ops = [] # 运算符栈
nums = [] # 数字栈
i = 0
n = len(expression)
while i < n:
if expression[i] == ' ':
i += 1
continue
if expression[i] == '(':
ops.append('(')
i += 1
elif expression[i] == ')':
# 处理括号内的表达式
while ops and ops[-1] != '(':
op = ops.pop()
right = nums.pop()
left = nums.pop()
nums.append(apply_operator(op, right, left))
ops.pop() # 弹出 '('
i += 1
elif expression[i] in '+-*/':
# 处理运算符
while (ops and ops[-1] != '(' and
precedence(ops[-1]) >= precedence(expression[i])):
op = ops.pop()
right = nums.pop()
left = nums.pop()
nums.append(apply_operator(op, right, left))
ops.append(expression[i])
i += 1
else:
# 处理数字,可能是多位数
num = 0
while i < n and expression[i].isdigit():
num = num * 10 + int(expression[i])
i += 1
nums.append(num)
# 最后处理栈中的剩余运算符
while ops:
op = ops.pop()
right = nums.pop()
left = nums.pop()
nums.append(apply_operator(op, right, left))
return nums[0]
#测试
if __name__ == "__main__":
print(solution("1+1") == 2)
print(solution("3+4*5/(3+2)") == 7)
print(solution("4+2*5-2/1") == 12)
print(solution("(1+(4+5+2)-3)+(6+8)") == 23)
代码说明
apply_operator: 用来执行加、减、乘、除运算。要注意的是,除法使用了整数除法,并处理了负数除法的情况precedence: 判断运算符的优先级,*和/优先级高于+和-- 主循环:
- 处理括号:遇到左括号时,将其压入运算符栈;遇到右括号时,直到遇到左括号为止,逐个执行栈中的运算符。
- 处理运算符:当遇到一个运算符时,先判断它的优先级,并决定是否执行栈中的运算符。
- 处理数字:通过遍历字符,获取连续的数字并转换成整数。
- 最后: 当所有字符都被处理后,栈中可能还剩下运算符,我们需要继续计算剩下的运算