LeetCode Lisp语法解析(细节处理)

版权声明:本文为博主原创文章,博客地址:https://blog.csdn.net/qq_41855420,未经博主允许不得转载。 https://blog.csdn.net/qq_41855420/article/details/89739280

给定一个类似 Lisp 语句的表达式 expression,求出其计算结果。
表达式语法如下所示:

  1. 表达式可以为整数,let 语法,add 语法,mult 语法。表达式的结果总是一个整数。(整数可以是正整数、负整数、0)
  2. let 语法表示为 (let v1 e1 v2 e2 … vn en expr), 其中 let语法总是以字符串
    "let"来表示,接下来会跟随一个或多个交替变量或表达式,也就是说,第一个变量 v1被分配为表达式 e1 的值,第二个变量 v2
    被分配为表达式 e2 的值,以此类推;最终 let 语法的值为 expr表达式的值。
  3. add语法表示为 (add e1 e2),其中 add 语法总是以字符串 "add"来表示,该语法总是有两个表达式e1、e2,
    该语法的最终结果是 e1 表达式的值与 e2 表达式的值之和。
  4. mult语法表示为 (mult e1 e2) ,其中 mult 语法总是以字符串"mult"表示, 该语法总是有两个表达式
    e1、e2,该语法的最终结果是 e1 表达式的值与 e2 表达式的值之积。
  5. 在该题目中,变量的命名以小写字符开始,之后跟随0个或多个小写字符或数字。为了方便,“add”,“let”,“mult"会被定义为"关键字”,不会在表达式的变量命名中出现。

最后,要说一下范围的概念。在做计算时,需要注意优先级,在最内层(根据括号)的表达式的值应该先计算,然后依次计算外层的表达式。我们将保证每一个测试的表达式都是合法的。有关范围的更多详细信息,请参阅示例。

示例:

输入: (add 1 2)
输出: 3
输入: (mult 3 (add 2 3))
输出: 15
输入: (let x 2 (mult x 5))
输出: 10
输入: (let x 2 (mult x (let x 3 y 4 (add x y))))
输出: 14
解释: 
表达式 (add x y), 在获取 x 值时, 我们应当由最内层依次向外计算, 首先遇到了 x=3, 所以此处的 x 值是 3.
输入: (let x 3 x 2 x)
输出: 2
解释: let 语句中的赋值运算按顺序处理即可
输入: (let x 1 y 2 x (add x y) (add x y))
输出: 5
解释: 
第一个 (add x y) 计算结果是 3,并且将此值赋给了 x 。
第二个 (add x y) 计算结果就是 3+2 = 5 。
输入: (let x 2 (add (let x 3 (let x 4 x)) x))
输出: 6
解释: 
(let x 4 x) 中的 x 的作用范围仅在()之内。所以最终做加法操作时,x 的值是 2 。
输入: (let a1 3 b2 (add a1 1) b2) 
输出: 4
解释: 
变量命名时可以在第一个小写字母后跟随数字.

注意:

我们给定的 expression 表达式都是格式化后的:表达式前后没有多余的空格,表达式的不同部分(关键字、变量、表达式)之间仅使用一个空格分割,并且在相邻括号之间也没有空格。我们给定的表达式均为合法的且最终结果为整数。
我们给定的表达式长度最多为 2000 (表达式也不会为空,因为那不是一个合法的表达式)。
最终的结果和中间的计算结果都将是一个 32 位整数。

思路分析: 这道题是典型的字符串细节处理问题,我们只要抓住每次处理一个"(…)",这个expression是会得到一个值,而只有add、mult、let三种操作。

首先介绍表达式的可能情况:
第一种:表达式是"(...)",按照三种基本操作递归处理得到表达式的值。
第二种:表达式是变量,直接返回变量对应的值,比如(let x 2 (add x 5)),let中赋值x = 2,则add(x, y)第一个参数表达式的值x = 2
第二种:表达式是常量,直接返回常量的值,比如(add 3 5),l则add(x, y)两个参数表达式都是常量x = 2, y = 3

下面是三种基本操作:
第一种:(add e1 e2),处理add,我们先处理e1、e2两个表达式,得到e1、e2两个表达式的值,进行加法计算,得到当前expression的值
第二种:(mult e1 e2),处理mult,我们先处理e1、e2两个表达式,得到e1、e2两个表达式的值,进行乘法法计算,得到当前expression的值。
第三种:(let v1 e1 v2 e2 ... vn en expr),对于(v1 e1),(v2,e2),(v3,e3), ... , (v n - 1,e n - 1),(v n,e n)这都是赋值操作,对于e1到en共n个表达式,我们分别求出这n个表达式的值,然后赋值到n个变量v1到vn即可,最后求出表达式expr的值就是当前expression的值。
class Solution {
public:
    int evaluate(string expression) {
        int nowIndex = 1;//即将处理的字符串下标,初始化为1,因为每个输入都有一个外加括号
        unordered_map<string, int> hashMap;//用于储存这个表达式中let赋值操作
        return myEvaluate(expression, nowIndex, hashMap);//开始处理一个expression
    }
    //开始处理以nowIndex为起始的一个expression
    int myEvaluate(string &expression, int &nowIndex, unordered_map<string, int> hashMap){
        if (expression[nowIndex] == 'a'){
            //第一种情况:处理add操作
            int firstNum = 0, secondNum = 0;
            nowIndex += 4;//跳过"add "
            //第一步:求add的第一个表达式参数的值
            if (expression[nowIndex] == '('){//第一个表达式也是"(...)",递归处理
                nowIndex += 1;//跳过左括号
                firstNum = myEvaluate(expression, nowIndex, hashMap);
            }
            else{//否则这个表达式是变量或者常量(表达式只有三种可能)
                firstNum = myFunc(expression, nowIndex, hashMap);
            }
            nowIndex += 1;//跳过空格
            //第二步:求add的第二个表达式参数的值
            if (expression[nowIndex] == '('){//第二个表达式也是"(...)",递归处理
                nowIndex += 1;//跳过左括号
                secondNum = myEvaluate(expression, nowIndex, hashMap);
            }
            else{//否则这个表达式是变量或者常量(表达式只有三种可能)
                secondNum = myFunc(expression, nowIndex, hashMap);
            }
            nowIndex += 1;//跳过右括号
            return firstNum + secondNum;//进行加法操作
        }
        else if (expression[nowIndex] == 'm'){
            //第二种情况:处理mult操作
            int firstNum = 0, secondNum = 0;
            nowIndex += 5;//跳过"mult "
            //第一步:求mult的第一个表达式参数的值
            if (expression[nowIndex] == '('){//第一个表达式也是"(...)",递归处理
                nowIndex += 1;//跳过左括号
                firstNum = myEvaluate(expression, nowIndex, hashMap);
            }
            else{//否则这个表达式是变量或者常量(表达式只有三种可能)
                firstNum = myFunc(expression, nowIndex, hashMap);
            }
            nowIndex += 1;//跳过空格
            //第二步:求mult的第二个表达式参数的值
            if (expression[nowIndex] == '('){//第二个表达式也是"(...)",递归处理
                nowIndex += 1;//跳过左括号
                secondNum = myEvaluate(expression, nowIndex, hashMap);
            }
            else{//否则这个表达式是变量或者常量(表达式只有三种可能)
                secondNum = myFunc(expression, nowIndex, hashMap);
            }
            nowIndex += 1;//跳过右括号
            return firstNum * secondNum;//进行乘法操作
        }
        else {
            //第三种情况:处理let操作(let v1 e1 v2 e2 ... vn en expr)
            //我们每次成对进行处理(v1 e1),(v2,e2),(v3,e3), ... , (v n - 1,e n - 1),(v n,e n),最后单出expr
            nowIndex += 4;//跳过"let "
            while (true){
                if (expression[nowIndex] == '('){
                    //let中的expr也是一个"(...)",递归处理
                    nowIndex += 1;
                    int tempRes = myEvaluate(expression, nowIndex, hashMap);
                    nowIndex += 1;//跳过右括号
                    return tempRes;
                }
                //下面将会每次处理一个变量一个表达式
                string str = "";
                while (expression[nowIndex] != ')' && expression[nowIndex] != ' '){
                    str += expression[nowIndex++];
                }
                if (expression[nowIndex] == ')'){
                    //遇到了右括号,则说明最后一个expr表达式是常量或者变量
                    nowIndex += 1;
                    if (hashMap.count(str)){
                        return hashMap[str];
                    }
                    else{
                        return atoi(str.c_str());
                    }
                }
                else{
                    //否则读取一个(变量 表达式)进行赋值操作
                    nowIndex += 1;
                    if (expression[nowIndex] == '('){//e n表达式也是"(...)",递归处理
                        nowIndex += 1;//跳过右括号
                        hashMap[str] = myEvaluate(expression, nowIndex, hashMap);
                    }
                    else{//e n表达式是变量或者常量(表达式只有三种可能)
                        hashMap[str] = myFunc(expression, nowIndex, hashMap);
                    }
                    nowIndex += 1;
                }
            }
        }
    }
    //读取nowIndex为起始下标的一个表达式(这个表达式是常量比如2,或者是一个在hashMap中的变量)
    int myFunc(string &expression, int &nowIndex, unordered_map<string, int> &hashMap){
        string str = "";
        while (expression[nowIndex] != ' ' && expression[nowIndex] != ')'){
            str += expression[nowIndex++];
        }
        if (hashMap.count(str)){//是一个在hashMap中的变量
            return hashMap[str];
        }
        else{//表达式是常量比如2
            return atoi(str.c_str());
        }
    }
};

在这里插入图片描述
这种题目一般都不是很难,就是细节处理需要严密的逻辑以及清新的思路。

猜你喜欢

转载自blog.csdn.net/qq_41855420/article/details/89739280