题目描述
思路解析动画文字版
括号 = “先把外面的进度存起来,进去单独算完再接回来”,这就是栈。
上排是整条表达式(固定不变),下面竖着的是栈,里面存“括号外面没算完的进度”。
碰到 ( :把“外面算到一半的 result 和 sign”整对压进栈,括号里从 0 干净地重新算。
第 1 个是数字 1,先攒着(num=1),等碰到符号或括号再结算。
碰到 +:把刚攒好的数按当前符号加进 result,再用 + 决定下一个数是正还是负。
碰到 ( :把“外面算到一半的 result 和 sign”整对压进栈,括号里从 0 干净地重新算。
第 4 个是数字 4,先攒着(num=4),等碰到符号或括号再结算。
碰到 +:把刚攒好的数按当前符号加进 result,再用 + 决定下一个数是正还是负。
第 6 个是数字 5,先攒着(num=5),等碰到符号或括号再结算。
碰到 +:把刚攒好的数按当前符号加进 result,再用 + 决定下一个数是正还是负。
第 8 个是数字 2,先攒着(num=2),等碰到符号或括号再结算。
碰到 ) :括号里这段算完了,弹出之前压的那对——括号值先乘上当时的符号,再加回当时的 result,进度就接上了。
碰到 -:把刚攒好的数按当前符号加进 result,再用 - 决定下一个数是正还是负。
第 11 个是数字 3,先攒着(num=3),等碰到符号或括号再结算。
碰到 ) :括号里这段算完了,弹出之前压的那对——括号值先乘上当时的符号,再加回当时的 result,进度就接上了。
碰到 +:把刚攒好的数按当前符号加进 result,再用 + 决定下一个数是正还是负。
碰到 ( :把“外面算到一半的 result 和 sign”整对压进栈,括号里从 0 干净地重新算。
第 15 个是数字 6,先攒着(num=6),等碰到符号或括号再结算。
碰到 +:把刚攒好的数按当前符号加进 result,再用 + 决定下一个数是正还是负。
第 17 个是数字 8,先攒着(num=8),等碰到符号或括号再结算。
最后一个 ) 把括号值合并回来后,整条表达式的结果就是 23。
边界先想清,尤其是负号和空格。
两个高频追问,第二问常被用来加难度。
参考代码
class Solution: def calculate(self, s: str) -> int: result, sign, num = 0, 1, 0 stack = [] for c in s: if c.isdigit(): num = num * 10 + int(c) elif c in "+-": result += sign * num num = 0 sign = 1 if c == "+" else -1 elif c == "(": stack.append(result); stack.append(sign) result, sign = 0, 1 elif c == ")": result += sign * num; num = 0 result *= stack.pop() # 栈顶 sign result += stack.pop() # 栈顶 result return result + sign * num复杂度
- 时间:O(n),每个字符只扫一次
- 空间:O(n),最坏全是左括号,全压进栈