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.LinkedList
class Solution {
internal class Exp(from: Exp?) {
var exps: Deque<Exp> = LinkedList()
var op: String? = null
var parent: Exp?
init {
parent = from
}
fun evaluate(vars: Map<String?, Int>): Int {
return if (op.equals("add", ignoreCase = true)) {
exps.pop().evaluate(vars) + exps.pop().evaluate(vars)
} else if (op.equals("mult", ignoreCase = true)) {
exps.pop().evaluate(vars) * exps.pop().evaluate(vars)
} else if (op.equals("let", ignoreCase = true)) {
val nextVars: MutableMap<String?, Int> = HashMap(vars)
while (exps.size > 1) {
val varName = exps.pop().op
val `val` = exps.pop().evaluate(nextVars)
nextVars[varName] = `val`
}
exps.pop().evaluate(nextVars)
} else {
if (Character.isLetter(op!![0])) {
vars[op]!!
} else {
op!!.toInt()
}
}
}
}
private fun buildTree(exp: String): Exp {
val root = Exp(null)
var cur: Exp? = root
var n = exp.length - 1
while (n >= 0) {
val c = exp[n]
if (c == ')') {
val next = Exp(cur)
cur!!.exps.push(next)
cur = next
} else if (c == '(') {
cur!!.op = cur.exps.pop().op
cur = cur.parent
} else if (c != ' ') {
var pre = n
while (pre >= 0 && exp[pre] != '(' && exp[pre] != ' ') {
pre--
}
val next = Exp(cur)
next.op = exp.substring(pre + 1, n + 1)
cur!!.exps.push(next)
n = pre + 1
}
n--
}
return root.exps.pop()
}
fun evaluate(exp: String): Int {
return buildTree(exp).evaluate(HashMap())
}
}