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"会被定义为"关键字”,不会在表达式的变量命名中出现。

最后,要说一下作用域的概念。计算变量名所对应的表达式时,在计算上下文中,首先检查最内层作用域(按括号计),然后按顺序依次检查外部作用域。我们将保证每一个测试的表达式都是合法的。有关作用域的更多详细信息,请参阅示例。

示例:

输入: (add 1 2)
输出: 3 输入: (mult 3 (add 2 3))
输出: 15 输入: (let x 2 (mult x 5))
输出: 10 输入: (let x 2 (mult x (let x 3 y 4 (add x y))))
输出: 14
解释:
表达式 (add x y), 在获取 x 值时, 我们应当由最内层依次向外计算, 首先遇到了 x=3, 所以此处的 x 值是 3. 输入: (let x 3 x 2 x)
输出: 2
解释: let 语句中的赋值运算按顺序处理即可 输入: (let x 1 y 2 x (add x y) (add x y))
输出: 5
解释:
第一个 (add x y) 计算结果是 3,并且将此值赋给了 x 。
第二个 (add x y) 计算结果就是 3+2 = 5 。 输入: (let x 2 (add (let x 3 (let x 4 x)) x))
输出: 6
解释:
(let x 4 x) 中的 x 的作用域仅在()之内。所以最终做加法操作时,x 的值是 2 。 输入: (let a1 3 b2 (add a1 1) b2)
输出: 4
解释:
变量命名时可以在第一个小写字母后跟随数字.

注意:

我们给定的 expression 表达式都是格式化后的:表达式前后没有多余的空格,表达式的不同部分(关键字、变量、表达式)之间仅使用一个空格分割,并且在相邻括号之间也没有空格。我们给定的表达式均为合法的且最终结果为整数。

我们给定的表达式长度最多为 2000 (表达式也不会为空,因为那不是一个合法的表达式)。

最终的结果和中间的计算结果都将是一个 32 位整数。

PS:

let 是 赋值语句

我也不清楚为什么,刚开始就是没看懂let(留下了菜鸟的眼泪)
class Solution {
public int evaluate(String expression) {
return eval(expression, new HashMap<>());
} private int eval(String exp, Map<String, Integer> parent) {
if (exp.charAt(0) != '(') {
if (exp.charAt(0) == '-' || Character.isDigit(exp.charAt(0))) {
return Integer.valueOf(exp);
}
return parent.get(exp);
}
Map<String, Integer> map = new HashMap<>();
map.putAll(parent);
List<String> list = parse(exp.substring(exp.charAt(1) == 'm' ? 6 : 5, exp.length() - 1));
//相加的语句
if (exp.startsWith("(a")) {
return eval(list.get(0), map) + eval(list.get(1), map);
//乘的语句
} else if (exp.startsWith("(m")) {
return eval(list.get(0), map) * eval(list.get(1), map);
} else {
//赋值语句
for (int i = 0; i < list.size() - 2; i += 2) {
map.put(list.get(i), eval(list.get(i + 1), map));
}
return eval(list.get(list.size() - 1), map);
}
}
//每一次拆分一个括号
private List<String> parse(String exp) {
List<String> res = new ArrayList<>();
StringBuilder sb = new StringBuilder();
int count = 0;
for (int i = 0; i < exp.length(); i++) {
char c = exp.charAt(i);
if (c == '(') count++;
else if (c == ')') count--;
if (c == ' ' && count == 0) {
res.add(sb.toString());
sb = new StringBuilder();
} else {
sb.append(c);
}
}
res.add(sb.toString());
return res;
}
}

Java实现 LeetCode 736 Lisp 语法解析(递归)的更多相关文章

  1. 用java实现一个简易编译器-语法解析

    语法和解析树: 举个例子看看,语法解析的过程.句子:“我看到刘德华唱歌”.在计算机里,怎么用程序解析它呢.从语法上看,句子的组成是由主语,动词,和谓语从句组成,主语是“我”,动词是“看见”, 谓语从句 ...

  2. [LeetCode] Parse Lisp Expression 解析Lisp表达式

    You are given a string expression representing a Lisp-like expression to return the integer value of ...

  3. [Swift]LeetCode736. Lisp 语法解析 | Parse Lisp Expression

    You are given a string expressionrepresenting a Lisp-like expression to return the integer value of. ...

  4. Java实现 LeetCode 385 迷你语法分析器

    385. 迷你语法分析器 给定一个用字符串表示的整数的嵌套列表,实现一个解析它的语法分析器. 列表中的每个元素只可能是整数或整数嵌套列表 提示:你可以假定这些字符串都是格式良好的: 字符串非空 字符串 ...

  5. Java实现 LeetCode 753 破解保险箱(递归)

    753. 破解保险箱 有一个需要密码才能打开的保险箱.密码是 n 位数, 密码的每一位是 k 位序列 0, 1, -, k-1 中的一个 . 你可以随意输入密码,保险箱会自动记住最后 n 位输入,如果 ...

  6. Java实现 LeetCode 654 最大二叉树(递归)

    654. 最大二叉树 给定一个不含重复元素的整数数组.一个以此数组构建的最大二叉树定义如下: 二叉树的根是数组中的最大元素. 左子树是通过数组中最大值左边部分构造出的最大二叉树. 右子树是通过数组中最 ...

  7. Atitit.sql ast 表达式 语法树 语法 解析原理与实现 java php c#.net js python

    Atitit.sql ast 表达式 语法树 语法 解析原理与实现 java php c#.net js python 1.1. Sql语法树 ast 如下图锁死1 2. SQL语句解析的思路和过程3 ...

  8. Java基础知识二次学习-- 第二章 基础语法与递归补充

    第二章 基础语法与递归补充   时间:2017年4月24日10:39:18 章节:02章_01节,02章_02节 视频长度:49:21 + 15:45 内容:标识符,关键字与数据类型 心得:由字母,下 ...

  9. 用java实现编译器-算术表达式及其语法解析器的实现

    大家在参考本节时,请先阅读以下博文,进行预热: http://blog.csdn.net/tyler_download/article/details/50708807 本节代码下载地址: http: ...

随机推荐

  1. 自动化运维工具Ansible之LNMP实践环境部署

    Ansible-实战指南-LNMP环境部署,并使用zabbix监控 主机规划 系统初始化:必要的系统初始化 基础组件包括:zabbix监控,mariadb(用于存放zabbix监控信息) 业务组件包括 ...

  2. indexDB出坑指南

    对于入了前端坑的同学,indexDB绝对是需要深入学习的. 本文针对indexDB的难点问题(事务和数据库升级)做了详细的讲解,而对于indexDB的特点和使用方法只简要的介绍了一下.如果你有一些使用 ...

  3. 帝国cms 批量删除包含关键字的 内容

    删除包含关键字的 内容delete from www_kaifatu_com_ecms_news where playurl like '%关键字%'

  4. buuctf-pwn刷题-axb_2019_heap

    版权声明:本文为CSDN博主「L.o.W」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明. 原文链接:https://blog.csdn.net/weixin_441 ...

  5. jconsole+idea监控+(jvisualvm 本地内存分析)

    1.idea启动配置 添加以下内容 -Djava.rmi.server.hostname=127.0.0.1 -Dcom.sun.management.jmxremote -Dcom.sun.mana ...

  6. .Net Core3.0 WebApi 项目框架搭建 二:API 文档神器 Swagger

    .Net Core3.0 WebApi 项目框架搭建:目录 为什么使用Swagger 随着互联网技术的发展,现在的网站架构基本都由原来的后端渲染,变成了:前端渲染.后端分离的形态,而且前端技术和后端技 ...

  7. 如何搭建一个WEB服务器项目(四)—— 实现安卓端图片加载

    使用Glide安卓图片加载库 观前提示:本系列文章有关服务器以及后端程序这些概念,我写的全是自己的理解,并不一定正确,希望不要误人子弟.欢迎各位大佬来评论区提出问题或者是指出错误,分享宝贵经验.先谢谢 ...

  8. ESXI 6.5利用Centos7重置root密码

    ESXI6.5宿主机,很久没有登录,再次登录的时候,发现忘记root密码了 1.先将刻录一个CentOS7的启动光盘或U盘,并将服务器的启动项修改为光盘 2.保存BIOS重启后,选择Troublesh ...

  9. k8s安装部署成功

  10. 关于idea的一次踩坑记录-Auto build completed with errors

    maven项目添加pom依赖后,一直不能正常导入所依赖的jar包,并且报错“ Auto build completed with errors”