736. Parse Lisp Expression
You are given a string
expressionrepresenting a Lisp-like expression to return the integer value of.The syntax for these expressions is given as follows.
- An expression is either an integer, a let-expression, an add-expression, a mult-expression, or an assigned variable. Expressions always evaluate to a single integer.
- (An integer could be positive or negative.)
- A let-expression takes the form
(let v1 e1 v2 e2 ... vn en expr), whereletis always the string"let", then there are 1 or more pairs of alternating variables and expressions, meaning that the first variablev1is assigned the value of the expressione1, the second variablev2is assigned the value of the expressione2, and so on sequentially; and then the value of this let-expression is the value of the expressionexpr.
- An add-expression takes the form
(add e1 e2)whereaddis always the string"add", there are always two expressionse1, e2, and this expression evaluates to the addition of the evaluation ofe1and the evaluation ofe2.
- A mult-expression takes the form
(mult e1 e2)wheremultis always the string"mult", there are always two expressionse1, e2, and this expression evaluates to the multiplication of the evaluation ofe1and the evaluation ofe2.
- For the purposes of this question, we will use a smaller subset of variable names. A variable starts with a lowercase letter, then zero or more lowercase letters or digits. Additionally for your convenience, the names "add", "let", or "mult" are protected and will never be used as variable names.
- Finally, there is the concept of scope. When an expression of a variable name is evaluated, within the context of that evaluation, the innermost scope (in terms of parentheses) is checked first for the value of that variable, and then outer scopes are checked sequentially. It is guaranteed that every expression is legal. Please see the examples for more details on scope.
Evaluation Examples:
Input: (add 1 2)
Output: 3 Input: (mult 3 (add 2 3))
Output: 15 Input: (let x 2 (mult x 5))
Output: 10 Input: (let x 2 (mult x (let x 3 y 4 (add x y))))
Output: 14
Explanation: In the expression (add x y), when checking for the value of the variable x,
we check from the innermost scope to the outermost in the context of the variable we are trying to evaluate.
Since x = 3 is found first, the value of x is 3. Input: (let x 3 x 2 x)
Output: 2
Explanation: Assignment in let statements is processed sequentially. Input: (let x 1 y 2 x (add x y) (add x y))
Output: 5
Explanation: The first (add x y) evaluates as 3, and is assigned to x.
The second (add x y) evaluates as 3+2 = 5. Input: (let x 2 (add (let x 3 (let x 4 x)) x))
Output: 6
Explanation: Even though (let x 4 x) has a deeper scope, it is outside the context
of the final x in the add-expression. That final x will equal 2. Input: (let a1 3 b2 (add a1 1) b2)
Output 4
Explanation: Variable names can contain digits after the first character.
Note:
- The given string
expressionis well formatted: There are no leading or trailing spaces, there is only a single space separating different components of the string, and no space between adjacent parentheses. The expression is guaranteed to be legal and evaluate to an integer.- The length of
expressionis at most 2000. (It is also non-empty, as that would not be a legal expression.)- The answer and all intermediate calculations of that answer are guaranteed to fit in a 32-bit integer.
Approach #1: String. [Java]
class Solution {
public int evaluate(String expression) {
return evaluate(expression, new HashMap<>());
}
private int evaluate(String e, Map<String, Deque<Integer>> map) {
char c = e.charAt(1); // the expression must start with "(add " or "(mult " or "(let ".
if (c == 'a') return evaluateAdd(e, map); // "add" expression
else if (c == 'm') return evaluateMult(e, map); // "mult" expression
else if (c == 'l') return evaluateLet(e, map); // "let" expression
else return 0; // illegal expression so return 0
}
private int evaluateAdd(String e, Map<String, Deque<Integer>> map) {
int offset = 5; // the expression starts with "(add ", so offset starts at 5.
String o1 = getOperand(e, offset); // first operand
offset += o1.length() + 1;
String o2 = getOperand(e, offset); // second operand
return evaluateOperand(o1, map) + evaluateOperand(o2, map);
}
private int evaluateMult(String e, Map<String, Deque<Integer>> map) {
int offset = 6;
String o1 = getOperand(e, offset);
offset += o1.length() + 1;
String o2 = getOperand(e, offset);
return evaluateOperand(o1, map) * evaluateOperand(o2, map);
}
private int evaluateLet(String e, Map<String, Deque<Integer>> map) {
List<String> variables = new ArrayList<>(); // list of variables assigned in this "let" expression
int res = 0; // the result of this "let" expression
int offset = 5; // the expression starts with "(let ", so offset starts at 5.
while (offset < e.length()) {
String o1 = getOperand(e, offset);
offset += o1.length() + 1;
String o2 = getOperand(e, offset);
if (o2 == null) { // if second operand is null, we reached the last operand
res = evaluateOperand(o1, map);
break;
}
offset += o2.length() + 1;
variables.add(o1); // record the variable
if (!map.containsKey(o1)) map.put(o1, new ArrayDeque<>());
map.get(o1).offerFirst(evaluateOperand(o2, map)); // do the assignment
}
// pop out assigned values before returning from this "let" expression
for (int i = variables.size() - 1; i >= 0; --i) {
String variable = variables.get(i);
Deque<Integer> stack = map.get(variable);
stack.pollFirst();
if (stack.isEmpty()) map.remove(variable);
}
return res;
}
private String getOperand(String e, int offset) {
if (offset >= e.length()) return null; // invalid offset
char c = e.charAt(offset);
int start = offset;
if (c == '-' || Character.isDigit(c)) { // operand is an integer
if (c == '-') offset++;
while (offset < e.length() && Character.isDigit(e.charAt(offset))) offset++;
} else if (Character.isLowerCase(c)) { // operand is a variable
while (offset < e.length() && Character.isLetterOrDigit(e.charAt(offset))) offset++;
} else { // operand is another expression enclosed in parenthses
for (int cnt = 0; offset < e.length(); ) {
c = e.charAt(offset++);
if (c == '(') cnt++;
if (c == ')') cnt--;
if (cnt == 0) break;
}
}
return e.substring(start, offset);
}
private int evaluateOperand(String e, Map<String, Deque<Integer>> map) {
char c = e.charAt(0);
if (c == '-' || Character.isDigit(c)) { // operand is an integer so parse it
return Integer.parseInt(e);
} else if (Character.isLowerCase(c)) { // operand is a variable so look it up
return map.get(e).peekFirst();
} else { // operand is another expression so evaluate it recursively
return evaluate(e, map);
}
}
}
Analysis:
These type of problems are notorious for their complex and intertwined nature. A modularized approach would certainly help to clarify the problem. So here is how I would divide the original problem into difference modules.
For an input string expression, we have the function evaluate to resolve its value.
The input expression must be one of the following three types of expressions -- add, mult and let. Correspondingly we will have three functions to evaluate each of them --evaluateAdd, evaluateMult and evaluateLet.
All the three types of expressions can be thought of as composed by operands, where each operand can be an integer, a variable or another expression of the three types mentioned above (note the expression will be enclosed in parentheses).
An add expression contains 2 operands and is evaluated to be the sum of the two operands.
A mult expression contains 2 operands and is evaluated to be the product of two operands.
A let expression contains 2m + 1 operands and is evaluated to be the value of the last operand. The first m pairs of operands correspond to m assignments. For each pair, the first operand is a variable while the second can be an integer, a variable or another expression. To simulate the assignment operations, we will maintain a HashMap, which maps the variable to the assigned values (this also implies the evaluate function in steep 1 should be delegated to a subroutine with an additional HashMap parameter). To simulate the concept of scope, the assigned values will be placed in a stack. Whenever the let expression returns. all assignments performed within it become invalid and should be popped out of the stack.
From the analyses above, given an expression e, we need to identify its constituent operands. We will have two functions serving for this purpose.
getOperand: this function will obtain the string representation of the operand starting from the specified offset into the expression e. It will distingguish the three types of operands -- an integer, a variable or another expression (of type add, mult or let).
evaluateOperand: This function will evaluate the operand string obtained above. For an operand of integer type, it will look up its value in the hash map; for an operand of expression type, it will recurively call the evaluate function to resolve its value.
Reference:
https://leetcode.com/problems/parse-lisp-expression/discuss/109718/Java-modularized-solution
736. Parse Lisp Expression的更多相关文章
- [LeetCode] Parse Lisp Expression 解析Lisp表达式
You are given a string expression representing a Lisp-like expression to return the integer value of ...
- [Swift]LeetCode736. Lisp 语法解析 | Parse Lisp Expression
You are given a string expressionrepresenting a Lisp-like expression to return the integer value of. ...
- Parse Lisp Expression
You are given a string expression representing a Lisp-like expression to return the integer value of ...
- 处理 javax.el.ELException: Failed to parse the expression 报错
在JSP的表达式语言中,使用了 <h3>是否新Session:${pageContext.session.new}</h3> 输出Session是否是新的,此时遇到了 j ...
- thymeleaf+layui加载页面渲染时TemplateProcessingException: Could not parse as expression
Caused by: org.attoparser.ParseException: Could not parse as expression: " {type: 'numbers'}, { ...
- org.thymeleaf.exceptions.TemplateProcessingException: Could not parse as expression:
org.thymeleaf.exceptions.TemplateProcessingException: Could not parse as expression:
- could not parse as expression: "/login" (template: "include/include" - line 32, col 42)
<li><a href="login.html" th:href="/login">登录</a></li> or ...
- layui表格数据渲染SpringBoot+Thymeleaf返回的数据时报错(Caused by: org.attoparser.ParseException: Could not parse as expression: ")
layui table渲染数据时报错(Caused by: org.attoparser.ParseException: Could not parse as expression: ") ...
- Tomcat报failed to parse the expression [${xxx}]异常(javax.el.ELException)的解决方法
Tomcat 7 'javax.el.ELException' 的解决方式tomcat 7对EL表达式的语法要求比较严格,例如"${owner.new}"因包含关键字new就会导致 ...
随机推荐
- a链接的onclick与js中的return false
在学习<javascript基础教程>第八版时,有一个小细节开始不是很明白,查了一些资料后,理了一下思路. 例子的html代码: <!DOCTYPE html> <htm ...
- django AnonymousUser
AnonymousUser对象class models.AnonymousUser django.contrib.auth.models.AnonymousUser是一个实现django.contri ...
- MySql中对Group by后的结果数进行Count
今天在写MySQ的SQL语句的时候遇到了一个奇怪的问题 select count(*) from subsitealbum t1, photo t2,files t3 where t1.SourceA ...
- MSTP+ VRRP 交换机的 配置过程
配置思路采用以下思路配置: 1.在处于环形网络中的交换设备上配置MSTP基本功能,包括:a.配置MST域并创建多实例,配置VLAN2映射到MSTI1,VLAN3映射到MSTI2,实现流量的负载分担. ...
- Http的缓存机制
最近参加一个面试,被面试官问到http的缓存机制,发现自己并不熟悉,于是这篇博客诞生了. HTTP是超文本传输协议,从万维网服务器传输文本到本地浏览器的传送协议,基于TCP/IP通信协议传递数据 HT ...
- 347. Top K Frequent Elements 最常用的k个元素
[抄题]: Given a non-empty array of integers, return the k most frequent elements. For example,Given [1 ...
- tp3.2 phpexcel 简单导出多个sheet(execl表格)
参考链接:https://blog.csdn.net/u011341352/article/details/70211962 以下是公共类PHPExcel.php文件: // 开始 <?php/ ...
- 六、maven仓库中安装没有的jar包
举例:安装dubbo.jar Dubbox 的 jar 包并没有部署到 Maven 的中央仓库中,大家在 Maven 的中央仓库中可以查找到 Dubbo 的最终版本是 2.5.3 , 阿里巴巴解散了 ...
- springboot 使用JPA自动生成Entity实体类的方法
1. 2. 3.添加数据库 4. 5. 6. 7.点击OK完成. 8.去掉红色波浪线方法. 9.配置数据源 完成!
- Eigen使用矩阵作为函数参数
1 使用矩阵作为函数参数介绍 文章来源Writing Functions Taking %Eigen Types as Parameters Eigen为了在函数中传递不同的类型使用了表达式模板技术. ...