|
| 1 | +/** |
| 2 | + * 736. Parse Lisp Expression |
| 3 | + * https://leetcode.com/problems/parse-lisp-expression/ |
| 4 | + * Difficulty: Hard |
| 5 | + * |
| 6 | + * You are given a string expression representing a Lisp-like expression to return the integer |
| 7 | + * value of. |
| 8 | + * |
| 9 | + * The syntax for these expressions is given as follows. |
| 10 | + * - An expression is either an integer, let expression, add expression, mult expression, or an |
| 11 | + * assigned variable. Expressions always evaluate to a single integer. |
| 12 | + * - (An integer could be positive or negative.) |
| 13 | + * - A let expression takes the form "(let v1 e1 v2 e2 ... vn en expr)", where let is always the |
| 14 | + * string "let", then there are one or more pairs of alternating variables and expressions, |
| 15 | + * meaning that the first variable v1 is assigned the value of the expression e1, the second |
| 16 | + * variable v2 is assigned the value of the expression e2, and so on sequentially; and then the |
| 17 | + * value of this let expression is the value of the expression expr. |
| 18 | + * - An add expression takes the form "(add e1 e2)" where add is always the string "add", there are |
| 19 | + * always two expressions e1, e2 and the result is the addition of the evaluation of e1 and the |
| 20 | + * evaluation of e2. |
| 21 | + * - A mult expression takes the form "(mult e1 e2)" where mult is always the string "mult", there |
| 22 | + * are always two expressions e1, e2 and the result is the multiplication of the evaluation of |
| 23 | + * e1 and the evaluation of e2. |
| 24 | + * - For this question, we will use a smaller subset of variable names. A variable starts with a |
| 25 | + * lowercase letter, then zero or more lowercase letters or digits. Additionally, for your |
| 26 | + * convenience, the names "add", "let", and "mult" are protected and will never be used as |
| 27 | + * variable names. |
| 28 | + * - Finally, there is the concept of scope. When an expression of a variable name is evaluated, |
| 29 | + * within the context of that evaluation, the innermost scope (in terms of parentheses) is |
| 30 | + * checked first for the value of that variable, and then outer scopes are checked sequentially. |
| 31 | + * It is guaranteed that every expression is legal. Please see the examples for more details |
| 32 | + * on the scope. |
| 33 | + */ |
| 34 | + |
| 35 | +/** |
| 36 | + * @param {string} expression |
| 37 | + * @return {number} |
| 38 | + */ |
| 39 | +var evaluate = function(expression) { |
| 40 | + return parse(expression, new Map()); |
| 41 | + |
| 42 | + function parse(exp, scope) { |
| 43 | + if (!isNaN(exp)) return parseInt(exp); |
| 44 | + if (!exp.startsWith('(')) return scope.get(exp) || 0; |
| 45 | + |
| 46 | + const tokens = tokenize(exp.slice(1, -1)); |
| 47 | + if (tokens[0] === 'add') return parse(tokens[1], scope) + parse(tokens[2], scope); |
| 48 | + if (tokens[0] === 'mult') return parse(tokens[1], scope) * parse(tokens[2], scope); |
| 49 | + |
| 50 | + const newScope = new Map(scope); |
| 51 | + for (let i = 1; i < tokens.length - 1; i += 2) { |
| 52 | + newScope.set(tokens[i], parse(tokens[i + 1], newScope)); |
| 53 | + } |
| 54 | + return parse(tokens[tokens.length - 1], newScope); |
| 55 | + } |
| 56 | + |
| 57 | + function tokenize(exp) { |
| 58 | + const result = []; |
| 59 | + let current = ''; |
| 60 | + let depth = 0; |
| 61 | + |
| 62 | + for (const char of exp) { |
| 63 | + if (char === ' ' && depth === 0) { |
| 64 | + result.push(current); |
| 65 | + current = ''; |
| 66 | + } else { |
| 67 | + current += char; |
| 68 | + if (char === '(') depth++; |
| 69 | + if (char === ')') depth--; |
| 70 | + } |
| 71 | + } |
| 72 | + result.push(current); |
| 73 | + return result; |
| 74 | + } |
| 75 | +}; |
0 commit comments