736. Lisp 语法解析 : DFS 模拟题

题目描述

这是 LeetCode 上的 736. Lisp 语法解析 ,难度为 困难。

Tag : 「DFS」、「模拟」、「哈希表」

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

表达式语法如下所示:

  • 表达式可以为整数,let 表达式,add 表达式,mult 表达式,或赋值的变量。表达式的结果总是一个整数。
  • (整数可以是正整数、负整数、000)
  • 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 表达式的值之 积 。
  • 在该题目中,变量名以小写字符开始,之后跟随 000 个或多个小写字符或数字。为了方便,”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<=20001 <= expression.length <= 20001<=expression.length<=2000
  • exprssion 中不含前导和尾随空格
  • expressoin 中的不同部分(token)之间用单个空格进行分隔
  • 答案和所有中间计算结果都符合 32-bit 整数范围

DFS 模拟

今天身体不舒服,不写太详细,题目不难,大家结合代码看吧。

设计函数 int dfs(int l, int r, Map map) 函数,代表计算 s[l…r]s[l…r]s[l…r] 的结果,答案为 dfs(0,n-1,map),其中 nnn 为字符串的长度。

根据传入的 [l,r][l, r][l,r] 是否为表达式分情况讨论:

  • 若 s[l]=(s[l] = (s[l]=(,说明是表达式,此时从 lll 开始往后取,取到空格为止(假设位置为 idx),从而得到操作 op(其中 op 为 let、add 或 mult 三者之一),此时 op 对应参数为 [idx+1,r 1][idx + 1, r – 1][idx+1,r 1],也就是需要跳过位置 rrr(即跳过 op 对应的 ) 符号);
  • 再根据 op 为何种操作进一步处理,我们设计一个「传入左端点找右端点」的函数 int getRight(int left, int end),含义为从 left 出发,一直往右找(不超过 end),直到取得合法的「子表达式」或「对应的值」。
  • // 对于 getRight 函数作用,给大家举个 理解吧,其实就是从 left 出发,找到合法的「子表达式」或「值」为止 // (let x 2 (mult x (let x 3 y 4 (add x y)))) // a b // 传入 a 返回 b,代表 [a, b) 表达式为 (mult x (let x 3 y 4 (add x y))) // (let x 2 (mult x (let x 3 y 4 (add x y)))) // ab // 传入 a 返回 b,代表 [a, b) 表达式为 x
  • 否则 s[l…r]s[l…r]s[l…r] 不是表达式,通过判断 s[l…r]s[l…r]s[l…r] 是否有被哈希表记录来得知结果:若在哈希表中有记录,结果为哈希表中的映射值,否则结果为本身所代表的数值。

需要注意,根据「作用域」的定义,我们不能使用全局哈希表,而要在每一层递归时,传入 clone 出来的 map。

代码:

class Solution { char[] cs; String s; public int evaluate(String _s) { s = _s; cs = s.toCharArray(); return dfs(0, cs.length – 1, new HashMap()); } int dfs(int l, int r, Map map) { if (cs[l] == ‘(‘) { int idx = l; while (cs[idx] != ‘ ‘) idx++; String op = s.substring(l + 1, idx); r–; // 判别为 “(let”、”(add” 或 “(mult” 后,跳过对应的 “)” if (op.equals(“let”)) { for (int i = idx + 1; i = r) return dfs(i, j – 1, new HashMap(map)); j++; i = j; j = getRight(i, r); int value = dfs(i, j – 1, new HashMap(map)); map.put(key, value); i = j + 1; } return -1; // never } else if (op.equals(“add”)) { int j = getRight(idx + 1, r); int a = dfs(idx + 1, j – 1, new HashMap(map)), b = dfs(j + 1, r, new HashMap(map)); return a + b; } else { int j = getRight(idx + 1, r); int a = dfs(idx + 1, j – 1, new HashMap(map)), b = dfs(j + 1, r, new HashMap(map)); return a * b; } } else { String cur = s.substring(l, r + 1); if (map.containsKey(cur)) return map.get(cur); return Integer.parseInt(cur); } } int getRight(int left, int end) { int right = left, score = 0; while (right <= end) { if (cs[right] == '(') { score++; right++; } else if (cs[right] == ')') { score–; right++; } else if (cs[right] == ' ') { if (score == 0) break; right++; } else { right++; } } return right; }}

  • 时间复杂度:除对表达式进行递归划分以外,还存在对 map 的每层拷贝操作,复杂度为 O(n2)O(n^2)O(n2)
  • 空间复杂度:O(n)O(n)O(n)

最后

这是我们「刷穿 LeetCode」系列文章的第 No.736 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。

在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。

为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:github.com/SharingSour… 。

在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。

原文链接:https://juejin.cn/post/7117155612231729160

郑重声明:本文内容及图片均整理自互联网,不代表本站立场,版权归原作者所有,如有侵权请联系管理员(admin#wlmqw.com)删除。
用户投稿
上一篇 2022年7月8日 09:24
下一篇 2022年7月8日 09:24

相关推荐

  • 存储过程语法(sql server存储过程语法)

    今天小编给各位分享存储过程语法的知识,其中也会对sql server存储过程语法进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧! oracle存储过程基本语法…

    2022年11月26日
  • 《宝可梦朱紫》索财灵硬币有什么用?索财灵硬币作用及获取

    宝可梦朱紫宝可梦索财灵是可以掉索财灵硬币的,不少玩家不知道这个精灵掉落的硬币有什么用,怎么获取,小编这里给大家带来了宝可梦朱紫索财灵硬币作用及获取,一起来看下文中具体介绍吧。 索财…

    2022年11月22日
  • 马斯克凌晨一点半晒“代码审查”现场,编排他的段子比疯狂星期四还多

    梦晨 Pine 发自 凹非寺 量子位 | 公众号 QbitAI 每一个真正会写代码的人,请在下午2点到总部10层报到。 每一个真正会写代码的人,请在下午2点到总部10层报到。 马斯…

    2022年11月21日
  • 有理数和无理数(有理数和无理数的区别)

    今天小编给各位分享有理数和无理数的知识,其中也会对有理数和无理数的区别进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧! 有理数和无理数是什么? 有理数指整数可…

    2022年11月21日
  • 什么是PID控制(pid是什么意思)

    (一)先来彻底搞懂PID到底是啥? 啥是PID? PID,就是“比例(proportional)、积分(integral)、微分(derivative)”,是一种很常见的控制算法。…

    2022年11月17日
  • 五金产品分类明细(五金都有什么)

    五金产品在我们家居装修以及家具选购的时候很是需要注意,因为五金产品很容易生锈,特别是埋在墙内或者地下的,坏了就需要费工夫去维修,所以需要好的五金产品,那么现在五金有哪些跟各有什么作…

    2022年11月14日
  • 加湿器的危害(加湿器的作用及好处)

    加湿器是北方小伙伴秋冬和换季必备的产品。虽然家庭普及率已经很高了,但是仍然有小伙伴心里犯嘀咕,到底有用没用?特别是随着科技的发展,加湿器已经由有雾的超声波加湿器,发展到无雾的蒸发型…

    2022年11月14日
  • 网站客服代码(网站客服代码实现移动端隐藏,电脑端展开)

    本文主要讲的是网站客服代码,以及和网站客服代码实现移动端隐藏,电脑端展开相关的知识,如果觉得本文对您有所帮助,不要忘了将本文分享给朋友。 在线客服系统代码是什么? 在线客服系统代码…

    2022年11月12日
  • 8字头股票什么意思(8字头股票什么意思呀)

    北京证券交易所股票是以4和8开头1北京证券交易所是以现有的新三板精选层为基础组建,进一步提升服务中小企业的能力,打造服务创新型中小企业主阵地北京证券交易所是因为我们国家要支持中小企…

    2022年11月11日
  • 《战神5》力量有什么用?力量作用介绍

    战神5力量有什么用?在游戏当中很多玩家还不清楚战神5力量作用,不同的属性有着不同的效果和内容,很多玩家还不清楚具体的效果是什么,下面一起来看一下战神5力量作用介绍。 战神5力量作用…

    2022年11月9日

联系我们

联系邮箱:admin#wlmqw.com
工作时间:周一至周五,10:30-18:30,节假日休息