1.思路要点
(1)Lisp语法采用嵌套表达式,总共的命令只有两类,数值操作(add和mult)和赋值操作(let),很容易想到递归的方法解决。
(2)假设只有数值操作,思路其实很简单,将表达式按括号一层层分开,判断当前命令是add还是mult后,直接对进行数值操作的值采用递归即可。即ans_add=add(值1)+add(值2)。分开的方式可采用标记计数,对一个按空格分开的表达式逐个字符读取,遇到一个左括号标记+1,遇到一个右括号标记-1,标记为0时返回当前读取过的所有字符。
(3)加入赋值操作后,我们依旧将表达式分开,但在判断出当前命令是let后,我们先对当前所有变量赋值,并将赋值内容以字典形式保存在一个栈中。接着对赋值剩余的表达式进行递归即可。
(4)由于子函数evaluate负责进行递归过程,那么在以上所有操作之前,我们需要在函数开始阶段对输入的内容进行判断,如果输入内容不是一串表达式而是一个数值或者变量,那么此时迭代已进行至底层,对数值我们直接返回,对变量,我们返回(3)中栈所储存的变量的值
2.代码分析
#生成栈,栈由字典构成,每个字典代表一个作用域
def implicit_scope(func):
def wrapper(*args):
args[0].scope.append({})
ans=func(*args)
args[0].scope.pop()
return ans
return wrapper
class Solution:
def __init__(self):
self.scope=[{}]
#函数装饰器,每次执行evaluate时先由implicit_scope生成对应作用域
@implicit_scope
def evaluate(self, expression):
#判断当前爹迭代是否进入底层
if not expression.startswith('('):
#是底层,判断是数值(-是负号)还是变量
if expression.isdigit() or expression[0]=='-':
#若为数值便直接输出,我们将输出统一为int方便计算
return int(expression)
else:
#由于是栈,我们将scope倒着读取
for local in reversed(self.scope):
if expression in local:
#若为变量,我们找出栈中优先级最高的value并返回
return local[expression]
#将表达式分开,每次输入不包含命令,将分开的表达式转为list方便处理
tokens = list(self.sparse(expression[5+(expression[1]=='m'):-1]))
if expression.startswith('(add'):
return self.evaluate(tokens[0])+self.evaluate(tokens[1])
elif expression.startswith('(mult'):
return self.evaluate(tokens[0])*self.evaluate(tokens[1])
#命令为let,假设此时token为[‘x’,‘2’,‘y’,‘3’,‘XXX’],令x=2,y=3作为字典入栈
else:
lentoken = len(tokens)
for index in range(0, lentoken-1, 2):
self.scope[-1][tokens[index]]=self.evaluate(tokens[index+1])
return self.evaluate(tokens[-1])
def sparse(self,expression):
tokens=expression.split()
mark=0
buffer=[]
for token in tokens:
buffer.append(token)
mark+=token.count('(')-token.count(')')
if mark==0:
#标记为0返回,我们采用生成器的方法将当前级别表达式(或者说当前括号内)的结果返回
yield " ".join(buffer)
#记得将buffer清空
buffer=[]
expression="(let x 7 -12)"
test=Solution()
ans=test.evaluate(expression)
print(ans)
代码参考:
Leetcode
链接:
https://leetcode-cn.com/problems/parse-lisp-expression/solution/lisp-yu-fa-jie-xi-by-leetcode/