每日一题:736. Lisp 语法解析

题目链接

力扣

题目描述

给你一个类似 Lisp 语句的字符串表达式 expression,求出其计算结果。

表达式语法如下所示:

表达式可以为整数,let 表达式,add 表达式,mult 表达式,或赋值的变量。表达式的结果总是一个整数。
(整数可以是正整数、负整数、0)
let 表达式采用 "(let v1 e1 v2 e2 ... vn en expr)" 的形式,其中 let 总是以字符串 "let"来表示,接下来会跟随一对或多对交替的变量和表达式,也就是说,第一个变量 v1被分配为表达式 e1 的值,第二个变量 v2 被分配为表达式 e2 的值,依次类推;最终 let 表达式的值为 expr表达式的值。
add 表达式表示为 "(add e1 e2)" ,其中 add 总是以字符串 "add" 来表示,该表达式总是包含两个表达式 e1、e2 ,最终结果是 e1 表达式的值与 e2 表达式的值之 和 。
mult 表达式表示为 "(mult e1 e2)" ,其中 mult 总是以字符串 "mult" 表示,该表达式总是包含两个表达式 e1、e2,最终结果是 e1 表达式的值与 e2 表达式的值之 积 。
在该题目中,变量名以小写字符开始,之后跟随 0 个或多个小写字符或数字。为了方便,"add" ,"let" ,"mult" 会被定义为 "关键字" ,不会用作变量名。
最后,要说一下作用域的概念。计算变量名所对应的表达式时,在计算上下文中,首先检查最内层作用域(按括号计),然后按顺序依次检查外部作用域。测试用例中每一个表达式都是合法的。有关作用域的更多详细信息,请参阅示例。
 
示例 1:

输入:expression = "(let x 2 (mult x (let x 3 y 4 (add x y))))"
输出:14
解释:
计算表达式 (add x y), 在检查变量 x 值时,
在变量的上下文中由最内层作用域依次向外检查。
首先找到 x = 3, 所以此处的 x 值是 3 。
示例 2:

输入:expression = "(let x 3 x 2 x)"
输出:2
解释:let 语句中的赋值运算按顺序处理即可。
示例 3:

输入:expression = "(let x 1 y 2 x (add x y) (add x y))"
输出:5
解释:
第一个 (add x y) 计算结果是 3,并且将此值赋给了 x 。 
第二个 (add x y) 计算结果是 3 + 2 = 5 。
 
提示:

1 <= expression.length <= 2000
exprssion 中不含前导和尾随空格
expressoin 中的不同部分(token)之间用单个空格进行分隔
答案和所有中间计算结果都符合 32-bit 整数范围
测试用例中的表达式均为合法的且最终结果为整数

解题思路

使用多层栈和字典处理每个括号内的部分
遇到左括号就新建一层栈, 遇到右括号就将当前层计算出结果, 并将结果压入上层栈顶
每一层的字典用于处理当前层的已知映射关系
额外提取parseValue()/addValue()/calResult()函数, 简化处理

代码

Python

class Solution:
    def evaluate(self, expression: str) -> int:
        stacks = []
        maps = []

        def parseValue(v, map):
            if type(v) is int or v[0] == "-" or v.isnumeric():
                return int(v)
            elif v in map:
                return map[v]
            else:
                return v

        def addValue(v, stack, map):
            op = stack[0]
            if op == "let" and len(stack) & 1:  # 奇数长度的stack不进行解析
                stack.append(v)
            else:
                v = parseValue(v, map)
                if op == "let":
                    map[stack[-1]] = v
                stack.append(v)

        def calResult(stack, map):
            op = stack[0]
            if op == "let":
                return parseValue(stack[-1], map)
            elif op == "add":
                return parseValue(stack[-2], map) + parseValue(stack[-1], map)
            else:
                return parseValue(stack[-2], map) * parseValue(stack[-1], map)

        for w in expression.split():
            if w[0] == "(":
                op = w[1:]
                stacks.append([op])
                nmap = maps[-1].copy() if maps else {}
                maps.append(nmap)
            elif w[-1] == ")":
                v = w[:w.find(")")]
                addValue(v, stacks[-1], maps[-1])
                for i in range(len(w))[::-1]:
                    if w[i] != ")":
                        break
                    res = calResult(stacks.pop(), maps.pop())
                    if stacks:
                        addValue(res, stacks[-1], maps[-1])
                    else:
                        return res
            else:
                addValue(w, stacks[-1], maps[-1])

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值