描述
题目本身比较长, 大意是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): |