LeetCode-in-Java

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