【字符串】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" 会被定义为 "关键字" ,不会用作变量名。
  • 最后,要说一下作用域的概念。计算变量名所对应的表达式时,在计算上下文中,首先检查最内层作用域(按括号计),然后按顺序依次检查外部作用域。测试用例中每一个表达式都是合法的。有关作用域的更多详细信息,请参阅示例。

示例 1:

输入:expression = "(let x 2 (mult x (let x 3 y 4 (add x y))))"
输出:14
解释:
计算表达式 (add x y), 在检查变量 x 值时,
在变量的上下文中由最内层作用域依次向外检查。
首先找到 x = 3, 所以此处的 x 值是 3 。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/parse-lisp-expression

解题思路

这道题核心就是递归调用字符串处理,按照不同的case做解析,目前自己通过调试和对比其他人的代码,基本完成该功能。

大致流程如下:

  1. 如果有左括号情况,则是表达式;按照 add、mult、let语法处理;其中add、mult处理逻辑只需要按照递归处理就可以完成。let语法要考虑:赋值操作、expr表达式(这个表达式可以式数字、变量、或者具体的expression);还要考虑赋值操作的作用范围,以及赋值操作的清理。
  2. 如果没有左括号,则考虑是否是变量还是数字,根据实际情况返回。
  3. 返回后需要将右括号删除,否则会导致程序异常。

代码实现


import java.util.*;

class Solution {

    int index = 0;
    Map<String, Deque<Integer>> scopeMap = new HashMap<>();

    public int evaluate(String expression) {

        if (expression.charAt(index) != '(') {
            if (isDigit(expression)) {
                return parseDigit(expression);
            } else {
                String var = parseVar(expression);
                return scopeMap.get(var).peek();
            }
        }


        index++;
        int res;
        if (expression.charAt(index) == 'a') {
            // add
            index += 4;

            int left = evaluate(expression);
            index++;
            int right = evaluate(expression);

            res = left + right;

        } else if (expression.charAt(index) == 'm') {
            // mult
            index += 5;

            int left = evaluate(expression);
            index++;
            int right = evaluate(expression);

            res = left * right;

        } else {
            // let
            index += 4;

            List<String> vars = new ArrayList<>();
            Integer value = null;
            while (true) {

                if (expression.charAt(index) == '(' || isDigit(expression)) {
                    res = evaluate(expression);
                    break;
                }


                {

                    // 怎么判断是变量还是expr
                    String var = parseVar(expression);
                    if (expression.charAt(index) == ')') {
                        res = scopeMap.get(var).peek();
                        break;
                    } else {

                        vars.add(var);
                        index++;
                        int v = evaluate(expression);

                        scopeMap.putIfAbsent(var, new ArrayDeque<>());
                        scopeMap.get(var).push(v);
                        index++;
                    }
                }
            }

            for (String var : vars) {
                scopeMap.get(var).pop();
            }

        }

        index++; // 关键点要移除右括号

        return res;

    }

    private int parseDigit(String expression) {
        int v = 1;
        if (expression.charAt(index) == '-') {
            v = -1;
            index++;
        }
        StringBuilder sb = new StringBuilder();
        while (expression.charAt(index) != ' ' && expression.charAt(index) != ')') {
            sb.append(expression.charAt(index++));
        }
        return v * Integer.parseInt(sb.toString());
    }

    private String parseVar(String expression) {
        StringBuilder sb = new StringBuilder();
        while (expression.charAt(index) != ' ' && expression.charAt(index) != ')') {
            sb.append(expression.charAt(index++));
        }
        return sb.toString();
    }

    boolean isDigit(String expression) {
        if (expression.charAt(index) == '-' || Character.isDigit(expression.charAt(index))) {
            return true;
        }
        return false;
    }

    public static void main(String[] args) {
        Solution solution = new Solution();
        System.out.println(solution.evaluate("(add 1 2)"));
        System.out.println(solution.evaluate("(let x 3 x 2 x)"));

        System.out.println(solution.evaluate("(let x 2 (mult x (let x 3 y 4 (add x y))))"));
        System.out.println(solution.evaluate("(let x 1 y 2 x (add x y) (add x y))"));
        System.out.println(solution.evaluate("(let x 2 (add (let x 3 (let x 4 x)) x))"));
    }
}

总结

这道题要处理的case很多,目前我是case by case处理的,整个结构写的比较乱,欢迎指证,或者给出更为清晰的解题思路。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值