Leetcode 736. Lisp 语法解析 C++

Leetcode 736. Lisp 语法解析

题目

给定一个类似 Lisp 语句的表达式 expression,求出其计算结果。

表达式语法如下所示:

表达式可以为整数,let 语法,add 语法,mult 语法,或赋值的变量。表达式的结果总是一个整数。
(整数可以是正整数、负整数、0)
let 语法表示为 (let v1 e1 v2 e2 … vn en expr), 其中 let语法总是以字符串 "let"来表示,接下来会跟随一个或多个交替变量或表达式,也就是说,第一个变量 v1被分配为表达式 e1 的值,第二个变量 v2 被分配为表达式 e2 的值,以此类推;最终 let 语法的值为 expr表达式的值。
add 语法表示为 (add e1 e2),其中 add 语法总是以字符串 "add"来表示,该语法总是有两个表达式e1、e2, 该语法的最终结果是 e1 表达式的值与 e2 表达式的值之和。
mult 语法表示为 (mult e1 e2) ,其中 mult 语法总是以字符串"mult"表示, 该语法总是有两个表达式 e1、e2,该语法的最终结果是 e1 表达式的值与 e2 表达式的值之积。
在该题目中,变量的命名以小写字符开始,之后跟随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位整数。

题解

递归实现
我们需要用一个哈希表记录变量的值
详细过程见代码

代码

	string getExpression(string expression,int &i){		//获取单个表达式,也就是单个由空格分割的操作或变量或值
        string ans;
        if(expression[i] != '('){		//不是(,则获取一个操作或变量或值,也就是遇到空格或)结束
            int j;
            for(j=i; j<expression.length(); j++)
                if(expression[j]==' ' || expression[j]==')'){
                    ans = expression.substr(i,j-i);
                    i = j+1;
                    break;
                }
            if(expression[i]==')') i++;
            return ans;
        }else{		//是(,则我们需要获取这个()中的表达式
            int l = 1,j = i+1;      // ( )
            while(l != 0){
                if(expression[j] == ')')    l--;
                if(expression[j] == '(')    l++;
                j++;
            }
            ans = expression.substr(i,j-i);
            i = j+1;
            return ans;
        }
        
    }
    
    int evaluate(string expression){
        unordered_map<string,int> id;
        return evaluate(expression,id);
    }

    
    int evaluate(string expression,unordered_map<string,int> id) {		//expression表示当前需要计算的表达式,id存放各变量的值
        int len = expression.length(),i = 1;
        string choice = getExpression(expression,i);		//获取操作
        if(choice == "add"){		//add操作
            string x = getExpression(expression,i);		//获取第一个加数
            int xNum;
            if(x[0] == '(') xNum = evaluate(x,id);		//获取变量是一个表达式,因此递归获取
            else if(id.count(x) == 0)    xNum = stoi(x);		//获取的是个数
            else    xNum = id[x];			//获取的是变量,通过哈希表找到它的值
            string y = getExpression(expression,i);		//获取第二个加数
            int yNum;
            if(y[0] == '(') yNum = evaluate(y,id);		//获取的是一个表达式,递归获取值
            else if(id.count(y) == 0)    yNum = stoi(y);		//获取的是个数
            else    yNum = id[y];		//获取的是一个变量,通过哈希表找它的值
            return xNum+yNum;
        }else if(choice == "mult"){		//乘运算
            string x = getExpression(expression,i);		//获取第一个因子
            int xNum;
            if(x[0] == '(') xNum = evaluate(x,id);			//是一个表达式,递归获取值
            else if(id.count(x) == 0)    xNum = stoi(x);		//是一个数
            else    xNum = id[x];		//是一个变量
            string y = getExpression(expression,i);		//获取第二个因子
            int yNum;
            if(y[0] == '(') yNum = evaluate(y,id);		//是一个表达式,递归获取值
            else if(id.count(y) == 0)    yNum = stoi(y);	//是一个数
            else    yNum = id[y];		//是一个变量
            return xNum*yNum;
        }else{				//赋值运算
            while(i < len){
                string now = getExpression(expression,i);		//获取变量也可能是最后一个表达式,需要返回最后一个表达式的值
                if(now[0] == '(')   now = to_string(evaluate(now,id));
                if(i == len){		//计算的最后一个表达式
                    if(id.count(now) == 0)  return stoi(now);
                    else    return id[now];
                }
                string numStr = getExpression(expression,i);		//获取值
                int num;
                if(numStr[0] == '(')   num = evaluate(numStr,id);		//是一个表达式,递归获取答案
                else if(id.count(numStr) != 0)   num = id[numStr];	//变量
                else    num = stoi(numStr);		//数

                id[now] = num;
            }
        }
        return -1;
    }

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/parse-lisp-expression
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值