展开
整个式子只有+ - ( ),如果我们把括号展开,那么可以遍历一次得到答案,即数字和符号的组合相加
例如 1+2+(3-(4+5)) = 1+2+3-4-5
,是+1 +2 +3 -4 -5
这些数字合起来
关键是我们怎么把括号展开同时给每个数字赋予正确的符号
数字的符号被两个因素影响
- 数字当前的符号
- 数字之前的符号
例如-(1+2)
中2的符号,第一点,2的符号是+
,第二点,2的符号受到了括号前-
的影响,综合下来2的符号是-
数字当前的符号很好判断,要么是正要么是负,但是数字之前的符号需要记录下来,每个括号成对出现,所以我们可以用栈来表示,遇到左括号时,当前符号入栈,遇到右括号时,栈顶符号弹出
经过以上分析,我们需要两个变量
sign = 1
ops = [1]
sign初始化为1,ops初始化为[1]
,这是因为我们为了方便处理-
开头的表达式,相当于在表达式前加上0
,变为以+
开头
ret = 0
n = len(s)
i = 0
while i < n:
if s[i] == ' ':
i += 1
elif s[i] == '+':
# +
pass
elif s[i] == '-':
# -
pass
elif s[i] == '(':
# 左括号
pass
elif s[i] == ')':
# 右括号
pass
else:
# 碰到数字
pass
然后我们逐个分析
如果是+:
由于+不会改变当前符号的性质,所以我们保持sign = ops[-1]
即可
如果是-:
由于-会反转符号,所以我们用sign = -ops[-1]
来记录当前符号
如果是(:
我们碰到了新的括号,当前的sign
对括号内的元素来说是之前的元素,我们用ops.append(sign)
来记录括号之外的符号
如果是):
括号对结束了,我们把栈顶元素弹出
如果碰到数字:
按照之前的分析,我们获取数字,然后统计结果 ret += sign*num
即可
上面的代码完善后变为
class Solution:
def calculate(self, s: str) -> int:
ops = [1]
sign = 1
ret = 0
n = len(s)
i = 0
while i < n:
if s[i] == ' ':
i += 1
elif s[i] == '+':
# +号继承之前的符号
sign = ops[-1]
i += 1
elif s[i] == '-':
# -号反转
sign = -ops[-1]
i += 1
elif s[i] == '(':
ops.append(sign)
i += 1
elif s[i] == ')':
ops.pop()
i += 1
else:
num = 0
while i<n and s[i].isdigit():
num = num*10 + ord(s[i]) - ord('0')
i+=1
ret += num*sign
return ret
逆波兰表达式
把合格的中缀表达式转换成后缀表达式,这类题都能这么解
150. 逆波兰表达式求值 是检验逆波兰表达式求值是否正确的题目