描述
题目本身比较长, 大意是parse一个lisp like的语言. 可以从样例中get到信息:
(add 1 2)
返回1+2 => 3.(mult 3 (add 2 3))
先计算2+3, 返回的5再和3相乘 => 15.(let x 2 (mult x 5))
x
被赋值2, 然后x
和5相乘等于10, 然后返回10. 注意let
语句如果变量个数是奇数个, 那么最后一个是返回值.(let x 3 x 2 x)
x
先被赋值3, 再被赋值2, 最后返回x
的值2.(let x 1 y 2 x (add x y) (add x y))
在计算内层的(add x y)
时用到了之前的赋值语句.(let x 1 y (let x 2 x) x)
首先x
被赋值1, 然后内层的(let x 2 x)
给x
赋值2并返回, 然后y
被赋值2. 最后x
的值应该是本层的值,与更深层的x
无关.
思路
这个题的重点感觉不仅仅是stack
本身, 更多在于函数作用域的理解.
首先我们需要用一个字典token
来存变量和值. 例如{x:12, y:34}
.
通过观察可以得知以下几点:
- 运算符只有三种
{add, mult, let}
, 其中add
和mult
只有两个操作数.let
可以有>=1
个操作数,但是我们可以每次两两处理来赋值, 最后return剩余的那个. - 每次
let
的开始, 都会进入一个新的作用域. 外层的变量仍然有效, 并允许暂时覆盖外层的变量. - 每次遇到右括号
)
意味着可以开始计算本层语句的值, 对于add
和mult
来说计算完直接返回就行. 不影响变量token
本身. 对于let
来说,计算完返回上一层时,需要重置token
. - 只有
let
语句有权更新token
. 并且每次let
后面积攒了两个操作数的时候, 需要及时更新token
, 否则进入新的作用域时, 可能会出现需要retrieve某个变量值但是找不到的情况. 例如(let x 2 (mult x 5))
.
所以我们用一个stack
来存当前读入的所有操作符和操作数(变量&值). 用一个token_stack
来存每个let
语句对应的当前token
. 遇到新的let
时把当前token
入栈, 遇到)
并pop出某个内层let
时,之前旧版本的token
出栈.
代码
1 | class Solution(object): |