736. Parse Lisp Expression
https://leetcode.com/problems/parse-lisp-expression/description/
写一个简易的lisp expr parser,要支持三种表达式: (add x y)表示x+y, (mul x y)表示x * y,(let var1 e1 var2 e2 ... last_expr)表示e1赋给var1, e2赋给var2...最后整个表达式的值为last_expr的值。虽然这里有很多括号,但和之前遇到过的eval basket之类的用stack evaluate常量表达式的题不一样,这里()并不表示优先级而是最为表达式的分隔符,且还引入了变量的概念。解法很直观,分治递归解每个子表达式,然后把每个返回值再拼起来解当前的表达式。为了支持变量,每个表达式当作一个函数看待,用deque模拟call stack存储每个表达式产生的变量。
代码参考了花花的。
/*
* @lc app=leetcode id=736 lang=cpp
*
* [736] Parse Lisp Expression
*
* https://leetcode.com/problems/parse-lisp-expression/description/
*
* algorithms
* Hard (45.07%)
* Likes: 183
* Dislikes: 152
* Total Accepted: 7.9K
* Total Submissions: 17.5K
* Testcase Example: '"(add 1 2)"'
*
*
* 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.
*
* An expression is either an integer, a let-expression, an add-expression, a
* mult-expression, or an assigned variable. Expressions always evaluate to a
* single integer.
*
* (An integer could be positive or negative.)
*
* A let-expression takes the form (let v1 e1 v2 e2 ... vn en expr), where let
* is always the string "let", then there are 1 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.
*
* An add-expression takes the form (add e1 e2) where add is always the string
* "add", there are always two expressions e1, e2, and this expression
* evaluates to the addition of the evaluation of e1 and the evaluation of e2.
*
* A mult-expression takes the form (mult e1 e2) where mult is always the
* string "mult", there are always two expressions e1, e2, and this expression
* evaluates to the multiplication of the evaluation of e1 and the evaluation
* of e2.
*
* For the purposes of this question, we will use a smaller subset of variable
* names. A variable starts with a lowercase letter, then zero or more
* lowercase letters or digits. Additionally for your convenience, the names
* "add", "let", or "mult" are protected and will never be used as variable
* names.
*
* Finally, there is the concept of scope. When an expression of a variable
* name is evaluated, within the context of that evaluation, the innermost
* scope (in terms of parentheses) is checked first for the value of that
* variable, and then outer scopes are checked sequentially. It is guaranteed
* that every expression is legal. Please see the examples for more details on
* scope.
*
*
* Evaluation Examples:
*
* Input: (add 1 2)
* Output: 3
*
* Input: (mult 3 (add 2 3))
* Output: 15
*
* Input: (let x 2 (mult x 5))
* Output: 10
*
* Input: (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.
*
* Input: (let x 3 x 2 x)
* Output: 2
* Explanation: Assignment in let statements is processed sequentially.
*
* Input: (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.
*
* Input: (let x 2 (add (let x 3 (let x 4 x)) x))
* Output: 6
* Explanation: Even though (let x 4 x) has a deeper scope, it is outside the
* context
* of the final x in the add-expression. That final x will equal 2.
*
* Input: (let a1 3 b2 (add a1 1) b2)
* Output 4
* Explanation: Variable names can contain digits after the first character.
*
*
*
* Note:
* The given string expression is well formatted: There are no leading or
* trailing spaces, there is only a single space separating different
* components of the string, and no space between adjacent parentheses. The
* expression is guaranteed to be legal and evaluate to an integer.
* The length of expression is at most 2000. (It is also non-empty, as that
* would not be a legal expression.)
* The answer and all intermediate calculations of that answer are guaranteed
* to fit in a 32-bit integer.
*
*/
class Solution {
public:
deque<unordered_map<string, int>> scopes;
int eval(const string &s, int &pos) {
// 支持遍历的call stack
scopes.push_front(unordered_map<string, int>());
int val = 0;
if (s[pos] == '(') ++pos;
const string t = token(s, pos);
if (t == "add") {
val = eval(s, ++pos) + eval(s, ++pos);
} else if (t == "mult") {
val = eval(s, ++pos) * eval(s, ++pos);
} else if (t == "let") {
string var;
// expecting " var1 exp1 var2 exp2 ... last_expr"
while (s[pos] != ')') {
++pos;
// 每个eval会消耗它自身的(),当pos在这里还遇到(说明它是last_expr
if (s[pos] == '(') {
val = eval(s, ++pos);
break;
}
// x (add x y) 的x 或 -12)的-12
var = token(s, pos);
// 是 -12)
if (s[pos] == ')') {
if (isalpha(var[0])) val = value(var);
else val = stoi(var);
break;
}
// (add x y)
val = scopes.front()[var] = eval(s, ++pos);
}
} else if (isalpha(t[0])) {
// var
val = value(t);
} else {
val = stoi(t);
}
if (s[pos] == ')') ++pos;
scopes.pop_front();
return val;
}
int value(const string &symbol) {
// 遍历call stack直到找到var的值
for (const auto &scope : scopes) {
if (scope.count(symbol)) return scope.at(symbol);
}
return 0;
}
string token(const string &s, int &pos) {
string token;
while (pos < s.length()) {
if (s[pos] == ')' || s[pos] == ' ') break;
token += s[pos++];
}
return token;
}
int evaluate(string expression) {
int pos = 0;
return eval(expression, pos);
}
};
Last updated
Was this helpful?