Leetcode 736. Lisp 语法解析
本文最后更新于185 天前,其中的信息可能已经过时,如有错误请发送邮件到2446865563@qq.com

1.题目基本信息

1.1.题目描述

给你一个类似 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.2.题目地址

https://leetcode.cn/problems/parse-lisp-expression/description/

2.解题方法

2.1.解题思路

递归

2.2.解题步骤

第一步,构建维护变量。指针i进行全局遍历表达式;使用scope维护各个域的变量值,使用"变量名->变量值的栈"的哈希表结构进行存储

第二步,设计递归函数。递归函数calc的定义:计算从i开始的当前域的值,并返回;实现:对指针i遍历到的每种情况进行分类讨论

  • 2.1.情况1:没有遇到"(",而是小写字母,则匹配变量名varName,并返回当前域中变量varName的值(注意这里的varName是表达式中的varName,包括直接返回的和参与计算的,对于键值对形式的变量名会在l开头的域中进行匹配)

  • 2.2.情况2:没有遇到"(",而是数字或者"-",则直接匹配数值,并返回数值

  • 2.3.情况3:遇到"(",后面跟着let。分为"变量名 变量值"、"变量名 变量表达式"、"变量名形式的expr表达式"、"(add/mult a b)形式的expr表达式"

  • 2.4.情况4:遇到"(",后面跟着add,递归计算后面的表达式,并进行相加返回

  • 2.5.情况5:遇到"(",后面跟着mult,递归计算后面的表达式,并相乘返回

  • 2.6.善后处理,跳过当前"("对应的")",并返回计算结果

3.解题代码

python3代码

from collections import defaultdict

class Solution:
    def evaluate(self, expression: str) -> int:
        # 思路:递归 O(n)
        n = len(expression)
        # 第一步,构建维护变量。指针i进行全局遍历表达式;使用scope维护各个域的变量值,使用"变量名->变量值的栈"的哈希表结构进行存储
        i = 0
        scope = defaultdict(list)
        # 第二步,设计递归函数。递归函数calc的定义:计算从i开始的当前域的值,并返回;实现:对指针i遍历到的每种情况进行分类讨论
        def calc():
            nonlocal i
            if expression[i] != "(":
                if expression[i].islower():
                    # 2.1.情况1:没有遇到"(",而是小写字母,则匹配变量名varName,并返回当前域中变量varName的值(注意这里的varName是表达式中的varName,包括直接返回的和参与计算的,对于键值对形式的变量名会在l开头的域中进行匹配)
                    varName = ""
                    while i < n and expression[i] != " " and expression[i] != ")":
                        varName += expression[i]
                        i += 1
                    return scope[varName][-1]
                else:
                    # 2.2.情况2:没有遇到"(",而是数字或者"-",则直接匹配数值,并返回数值
                    flag = 1
                    if expression[i] == "-":
                        flag = -1
                        i += 1
                    num = 0
                    while expression[i].isdigit():
                        num = num * 10 + int(expression[i])
                        i += 1
                    return num * flag
            else:
                i += 1  # 跳过括号
                result = 0
                # 2.3.情况3:遇到"(",后面跟着let。分为"变量名 变量值"、"变量名 变量表达式"、"变量名形式的expr表达式"、"(add/mult a b)形式的expr表达式"
                if expression[i] == "l":
                    i += 4  # 跳过"let "
                    varNames = []   # 存储当前域变量名,为了后续当前域计算完成后恢复scope
                    while True:
                        # 循环匹配变量和表达式
                        if not expression[i].islower():
                            # 非变量名情况,即表达式,包括()表达式和数字表达式两种
                            result = calc()
                            break
                        else:
                            varName = ""
                            while expression[i] != " " and expression[i] != ")":
                                varName += expression[i]
                                i += 1
                            # 第3种表达式情况,匹配完成情况,即")"情况,由于发生在varName匹配后,所以这是个变量形式的返回表达式进行返回
                            if expression[i] == ")":
                                result = scope[varName][-1]
                                break
                            i += 1  # 跳过变量名后的空格
                            varValue = calc()   # 匹配数字或者递归计算表达式
                            scope[varName].append(varValue)     # 将匹配到变量压入栈中
                            i += 1  # 跳过变量数值或者表达式后的空格
                            varNames.append(varName)
                    # 在该以let开头的域计算完成后,释放该域中的局部变量
                    for varName in varNames:
                        scope[varName].pop()
                # 2.4.情况4:遇到"(",后面跟着add,递归计算后面的表达式,并进行相加返回
                elif expression[i] == "a":
                    i += 4  # 跳过"add "
                    val1 = calc()
                    i += 1  # 跳过空格
                    val2 = calc()
                    result = val1 + val2
                # 2.5.情况5:遇到"(",后面跟着mult,递归计算后面的表达式,并相乘返回
                elif expression[i] == "m":
                    i += 5
                    val1 = calc()
                    i += 1
                    val2 = calc()
                    result = val1 * val2
                # 2.6.善后处理,跳过当前"("对应的")",并返回计算结果
                i += 1  # 跳过")"
                return result
        return calc()

4.执行结果

觉得有帮助可以投喂下博主哦~感谢!

作者:geek007

转载请注明文章地址及作者哦~
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇