LeetCode in Kotlin

736. Parse Lisp Expression

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.

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:

Solution

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())
    }
}