[LeetCode解题报告] 736. Lisp 语法解析

一、 题目

1. 题目描述

  1. 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” 来表示,该表达式总是包含两个表达式 e1e2 ,最终结果是 e1 表达式的值与 e2 表达式的值之 **和 **。
  • mult 表达式表示为 “(mult e1 e2)” ,其中 mult 总是以字符串 “mult” 表示,该表达式总是包含两个表达式 e1e2,最终结果是 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 整数范围
  • 测试用例中的表达式均为合法的且最终结果为整数

2. 原题链接

链接: 736. Lisp 语法解析

二、 解题报告

1. 思路分析

这题敲+debug一个多小时,人麻了。
  • 没什么好思路,遇到括号就dfs一个表达式。
  • 然后硬做。
  • 简直是面向测试用例编程。
  • 定义一个全局的指针i,不断后移。
  • 定义一个key的字典,向下传递,接收时update,本作用域可以覆盖,不影响上一层。
  • 如果遇到add, 向后找两个部分,每个部分都:判断括号递归,否则就直接计算表达式的值。
  • mult同上。
  • let复杂一点,需要无限循环,每次找两个部分p1\p2,如果没有p2(i指针到了右括号),返回p1的值;如果有,让给p1赋值为p2。
  • 表达式需要判断是否是数字,直接转int,否则去key字典里映射。
  • python判断数字实测,isdigit\isnumeric都没用,这俩函数的意义是字符串里只含有数字,负号处理不了,因此自己封装一个。
  • 每次dfs后i会处在内部表达式的右括号,后边会有空格,因此i再加个1。
    在这里插入图片描述

2. 复杂度分析

最坏时间复杂度O(n)

3. 代码实现

dfs

class Solution:
    def evaluate(self, expression: str) -> int:
        n = len(expression)
        i = 0
        def is_num(x):
            return x.isdigit() or (len(x)>1 and x[0] == '-' and x[1:].isdigit())
        def dfs(l,params):
            ps = {}
            ps.update(params)
            nonlocal i
            
            if expression[l+1] == 'l':
                i = l+5
                while True:                        
                    p1 = ''
                    if expression[i] == '(':
                        p1 = dfs(i,ps)
                        i += 1
                        return p1
                    else:
                        while expression[i] not in  {' ',')'}:
                            p1 += expression[i]
                            i += 1
                    if expression[i] == ')':
                        if is_num(p1):
                            p1 = int(p1)
                        else:
                            p1 = ps[p1]
                        return p1
                    i += 1
                    p2 = ''
                    if expression[i] == '(':
                        # print(i)
                        p2 = dfs(i,ps)
                        i += 1
                        # print(i,p2)
                    else:
                        while expression[i] != ' ':
                            p2 += expression[i]
                            i += 1
                            # print(i)
                        if is_num(p2):
                            p2 = int(p2)
                        else:
                            p2 = ps[p2]
                    ps[p1] = int(p2)    
                    i+=1
                
            elif expression[l+1] == 'a':
                i = l+5
                p1,p2 = '',''
                if expression[i] == '(':
                    p1 = dfs(i,ps)
                    i+=1
                else:
                    while expression[i] != ' ':
                        p1 += expression[i]
                        i += 1
                    if is_num(p1):
                        p1 = int(p1)
                    else:
                        p1 = ps[p1]
                # print(p1,i,expression[i])
                if expression[i] != ' ':
                    i += 1
                i += 1
                
                # print(p1,i,expression[i])
                if expression[i] == '(':
                    p2 = dfs(i,ps)
                    i+=1
                else:
                    while expression[i] != ')':
                        p2 += expression[i]
                        i += 1
                    # print(i,expression[i])
                    if is_num(p2):
                        p2 = int(p2)
                    else:
                        p2 = ps[p2]
                return p1+p2                             

            elif expression[l+1] == 'm':
                i = l+6
                p1,p2 = '',''
                if expression[i] == '(':
                    p1 = dfs(i,ps)
                    i += 1
                else:
                    while expression[i] != ' ':
                        p1 += expression[i]
                        i += 1
                    if is_num(p1):
                        p1 = int(p1)
                    else:
                        p1 = ps[p1]

                if expression[i] == ' ':
                    i += 1
                
                if expression[i] == '(':
                    p2 = dfs(i,ps)
                    i+=1
                else:
                    while expression[i] != ')':
                        p2 += expression[i]
                        i += 1
                    if is_num(p2):
                        p2 = int(p2)
                    else:
                        p2 = ps[p2]
                return p1*p2              

        return dfs(0,{})


三、 本题小结

  1. debug麻了。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值