Hard
You are given a string expression representing a Lisp-like expression to return the integer value of.
The syntax for these expressions is given as follows.
"(let v1 e1 v2 e2 ... vn en expr)"
, where let is always the string "let"
, then there are one or more pairs of alternating variables and expressions, meaning that the first variable v1
is assigned the value of the expression e1
, the second variable v2
is assigned the value of the expression e2
, and so on sequentially; and then the value of this let expression is the value of the expression expr
."(add e1 e2)"
where add is always the string "add"
, there are always two expressions e1
, e2
and the result is the addition of the evaluation of e1
and the evaluation of e2
."(mult e1 e2)"
where mult is always the string "mult"
, there are always two expressions e1
, e2
and the result is the multiplication of the evaluation of e1 and the evaluation of e2."add"
, "let"
, and "mult"
are protected and will never be used as variable names.Example 1:
Input: expression = “(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.
Example 2:
Input: expression = “(let x 3 x 2 x)”
Output: 2
Explanation: Assignment in let statements is processed sequentially.
Example 3:
Input: expression = “(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.
Constraints:
1 <= expression.length <= 2000
expression
.expression
.import java.util.Deque;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
public class Solution {
static class Exp {
Deque<Exp> exps;
String op;
Exp parent;
public Exp(Exp from) {
this.exps = new LinkedList<>();
this.parent = from;
}
private int evaluate(Map<String, Integer> vars) {
if (op.equalsIgnoreCase("add")) {
return exps.pop().evaluate(vars) + exps.pop().evaluate(vars);
} else if (op.equalsIgnoreCase("mult")) {
return exps.pop().evaluate(vars) * exps.pop().evaluate(vars);
} else if (op.equalsIgnoreCase("let")) {
Map<String, Integer> nextVars = new HashMap<>(vars);
while (exps.size() > 1) {
String varName = exps.pop().op;
int val = exps.pop().evaluate(nextVars);
nextVars.put(varName, val);
}
return exps.pop().evaluate(nextVars);
} else {
if (Character.isLetter(op.charAt(0))) {
return vars.get(op);
} else {
return Integer.parseInt(op);
}
}
}
}
private Exp buildTree(String exp) {
Exp root = new Exp(null);
Exp cur = root;
int n = exp.length() - 1;
while (n >= 0) {
char c = exp.charAt(n);
if (c == ')') {
Exp next = new Exp(cur);
cur.exps.push(next);
cur = next;
} else if (c == '(') {
cur.op = cur.exps.pop().op;
cur = cur.parent;
} else if (c != ' ') {
int pre = n;
while (pre >= 0 && exp.charAt(pre) != '(' && exp.charAt(pre) != ' ') {
pre--;
}
Exp next = new Exp(cur);
next.op = exp.substring(pre + 1, n + 1);
cur.exps.push(next);
n = pre + 1;
}
n--;
}
return root.exps.pop();
}
public int evaluate(String exp) {
return buildTree(exp).evaluate(new HashMap<>());
}
}