问题描述
小F面临一个编程挑战:实现一个基本的计算器来计算简单的字符串表达式的值。该字符串表达式有效,并可能包含数字(0-9)、运算符+
、-
及括号()
。注意,字符串中不包含空格。除法运算应只保留整数结果。请实现一个解析器计算这些表达式的值,且不使用任何内置的eval
函数。
测试样例
样例1:
输入:
expression = "1+1"
输出:2
样例2:
输入:
expression = "3+4*5/(3+2)"
输出:7
样例3:
输入:
expression = "4+2*5-2/1"
输出:12
样例4:
输入:
expression = "(1+(4+5+2)-3)+(6+8)"
输出:23
样例5:
输入:
expression = "2*(5+5*2)/3+(6+8*3)"
输出:40
问题分析
小F面临的编程挑战是实现一个基本的计算器来计算简单字符串表达式的值。这个问题涉及到字符串处理、运算符优先级和基本的算术运算。关键在于如何正确地解析字符串表达式,并按照运算符的优先级执行计算。
解题思路
-
解析字符串表达式:
- 遍历字符串表达式,识别数字和运算符。
- 使用两个栈:一个用于存储数字(num_stack),另一个用于存储运算符(op_stack)。
-
处理数字:
- 当遇到连续的数字时,解析出完整的数字并压入 num_stack。
-
处理运算符:
- 当遇到运算符时,根据运算符优先级决定是立即执行运算还是将其压入 op_stack。
- 如果当前运算符的优先级高于 op_stack 栈顶的运算符,则将其压入 op_stack。
- 如果当前运算符的优先级低于或等于 op_stack 栈顶的运算符,则从 op_stack 弹出运算符并执行计算,直到当前运算符可以压入 op_stack。
-
处理括号:
- 当遇到左括号时,直接将其压入 op_stack。
- 当遇到右括号时,执行 op_stack 中所有运算,直到遇到左括号。
-
计算结果:
- 在字符串表达式遍历完成后,执行 op_stack 中剩余的运算。
- 最终 num_stack 栈顶的元素即为表达式的计算结果。
解题代码
def solution(expression):
def calculate(num_stack, op_stack):
op = op_stack.pop()
num2 = num_stack.pop()
num1 = num_stack.pop()
if op == '+':
num_stack.append(num1 + num2)
elif op == '-':
num_stack.append(num1 - num2)
elif op == '*':
num_stack.append(num1 * num2)
elif op == '/':
num_stack.append(int(num1 / num2)) # 使用 int() 来模拟数学除法后的向下取整
def get_priority(op):
if op in ('+', '-'):
return 1
elif op in ('*', '/'):
return 2
return 0
num_stack = []
op_stack = []
i = 0
while i < len(expression):
char = expression[i]
if char.isdigit(): # 如果是数字
num = 0
while i < len(expression) and expression[i].isdigit():
num = num * 10 + int(expression[i])
i += 1
num_stack.append(num)
continue
if char in ('+', '-', '*', '/', '(', ')'): # 如果是运算符
if char == '(':
op_stack.append(char)
elif char == ')':
while op_stack[-1] != '(':
calculate(num_stack, op_stack)
op_stack.pop() # 移除 '('
else:
while op_stack and get_priority(char) <= get_priority(op_stack[-1]):
calculate(num_stack, op_stack)
op_stack.append(char)
i += 1
while op_stack: # 处理剩余的运算符
calculate(num_stack, op_stack)
return num_stack[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)
总结
时间复杂度:
- 遍历字符串表达式的时间复杂度为 O(n),其中 n 是字符串的长度。
- 每个数字和运算符最多被处理一次,因此计算的时间复杂度也是 O(n)。
- 因此,总的时间复杂度为 O(n)。
空间复杂度:
- 需要两个栈来存储数字和运算符,最坏情况下,数字和运算符的数量都与字符串长度相同,因此空间复杂度为 O(n)。