【栈】736. Lisp 语法解析

news2025/3/15 4:22:12

本文涉及知识点

LeetCode736. 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 。
示例 2:

输入:expression = “(let x 3 x 2 x)”
输出:2
解释:let 语句中的赋值运算按顺序处理即可。
示例 3:

输入:expression = “(let x 1 y 2 x (add x y) (add x y))”
输出:5
解释:
第一个 (add x y) 计算结果是 3,并且将此值赋给了 x 。
第二个 (add x y) 计算结果是 3 + 2 = 5 。

提示:

1 <= expression.length <= 2000
exprssion 中不含前导和尾随空格
expressoin 中的不同部分(token)之间用单个空格进行分隔
答案和所有中间计算结果都符合 32-bit 整数范围
测试用例中的表达式均为合法的且最终结果为整数

包括 标识符(变量关键字) 常量 ( )
递归解析每个括号。unorder_map<string,stack> m_mVar 记录各变量的值。
一个括号从左到右解析,解析到变量入栈,本括号解析结束出栈。注意:不能先解析最内层括号,比如:(let x 2 add(x 1)) 先解析add会检测到未定义变量,而误认为是非法字符串。
Parse 函数大致流程:
一,如果有前置空格,忽略。忽略左括号。
二,解析命令名。
三,如果是加或乘法,读取两个值。并返回结果。
四,读取变量,如果失败则读值。
五,忽略空格后,如果是右括号。则计算返回值,并变量出栈。
六,忽略空格后,如果不是右括号。读取值,更新变量的值,并入栈。

IgronSpace :如果有空格,则忽略。
GetNum1:读取值,包括变量 常量 表达式。
ParseName:解析变量名,字母开始,后效字符可以是字母,也可以是数字。
ParseNum:解析数字和表达式。
注意:iPos指向下一个待处理的字符。

代码

核心代码

class Solution {
public:
	int evaluate(string expression) {
		m_exp = expression;
		int iPos = 0;
		return Parse(iPos);
	}
	int Parse(int& iPos) {
		auto tmp = m_exp.substr(iPos);
		while ((iPos < m_exp.length()) && ('(' != m_exp[iPos])) {
			iPos++;
		}
		iPos += 1;//跳过(和空格
		string strName = ParseName(iPos);
		iPos++;
		if ("mult" == strName) {
			int num1 = GetNum1(iPos);
			int num2 = GetNum1(++iPos);
			IgronSpace(iPos);
			iPos++;
			return num1 * num2;
		}
		if ("add" == strName) {
			int num1 = GetNum1(iPos);
			int num2 = GetNum1(++iPos);
			IgronSpace(iPos);
			iPos++;
			return num1 + num2;
		}
		assert("let" == strName);
		vector<string> vars;
		while (true) {
			auto iRet = 0;
			string strVarName = ParseName(iPos);
			if ("" != strVarName) {
				IgronSpace(iPos);					
			}
			else {
				iRet += GetNum1(iPos);
				IgronSpace(iPos);
			}
			if (')' == m_exp[iPos]) { 
				if ("" != strVarName)
				{
					iRet = m_mVar[strVarName].top();
				}
				for (auto var : vars) {//变量出栈
					m_mVar[var].pop();
				}
				iPos++;
				return  iRet;
			}
			vars.emplace_back(strVarName);
			const int cur = GetNum1(iPos);
			m_mVar[strVarName].emplace();
			m_mVar[strVarName].top() = cur;
			iPos++;
		}
	}
	void IgronSpace(int& iPos) {
		if((iPos < m_exp.length())&&(' ' == m_exp[iPos])){iPos++;};
	}
	int GetNum1(int& iPos) {
		string strName = ParseName(iPos);
		if ("" != strName) { return m_mVar[strName].top(); }
		return ParseNum(iPos);
	}
	string ParseName(int& iPos) {
		string strName;
		while ((isalpha(m_exp[iPos]))||(strName.size() && isalnum(m_exp[iPos]))) {
			strName += m_exp[iPos++];
		}
		return strName;
	}
	int ParseNum(int& iPos) {
		int num = 0;
		if ('(' == m_exp[iPos]) { return Parse(iPos); }
		int iSign = 1;
		if ('-' == m_exp[iPos]) {
			iSign = -1; iPos++;
		}
		while (isdigit(m_exp[iPos])) {
			num = num*10+ (m_exp[iPos]-'0');
			iPos++;
		}
		return iSign* num;
	}
	unordered_map<string, stack<int>> m_mVar;
	string m_exp;
};

单元测试

template<class T1,class T2>
void AssertEx(const T1& t1, const T2& t2)
{
	Assert::AreEqual(t1 , t2);
}

template<class T>
void AssertEx(const vector<T>& v1, const vector<T>& v2)
{
	Assert::AreEqual(v1.size(), v2.size());	
	for (int i = 0; i < v1.size(); i++)
	{
		Assert::AreEqual(v1[i], v2[i]);
	}
}

template<class T>
void AssertV2(vector<vector<T>> vv1, vector<vector<T>> vv2)
{
	sort(vv1.begin(), vv1.end());
	sort(vv2.begin(), vv2.end());
	Assert::AreEqual(vv1.size(), vv2.size());
	for (int i = 0; i < vv1.size(); i++)
	{
		AssertEx(vv1[i], vv2[i]);
	}
}

namespace UnitTest
{
	string expression;
	TEST_CLASS(UnitTest)
	{
	public:
		TEST_METHOD(TestMethod0)
		{
			expression = "(let x 2 (mult x (let x 3 y 4 (add x y))))";
			auto res = Solution().evaluate(expression);
			AssertEx(14,res);
		}
		TEST_METHOD(TestMethod1)
		{
			expression = "(let x 3 x 2 x)";
			auto res = Solution().evaluate(expression);
			AssertEx(2, res);
		}
		TEST_METHOD(TestMethod2)
		{
			expression = "(let x 1 y 2 x (add x y) (add x y))";
			auto res = Solution().evaluate(expression);
			AssertEx(5, res);
		}
		TEST_METHOD(TestMethod3)
		{
			expression = "(let x 7 -12)";
			auto res = Solution().evaluate(expression);
			AssertEx(-12, res);
		}
		TEST_METHOD(TestMethod5)
		{
			expression = "(let x 2 (add (let x 3 (let x 4 x)) x))";
			auto res = Solution().evaluate(expression);
			AssertEx(6, res);
		}
		TEST_METHOD(TestMethod6)
		{
			expression = "(let x 2 (add (let x 3 4) x))";
			auto res = Solution().evaluate(expression);
			AssertEx(6, res);
		}
		TEST_METHOD(TestMethod7)
		{
			expression = "(let x 2 (add 4 x))";
			auto res = Solution().evaluate(expression);
			AssertEx(6, res);
		}
		TEST_METHOD(TestMethod8)
		{
			expression = "(let a1 3 b2 (add a1 1) b2)";
			auto res = Solution().evaluate(expression);
			AssertEx(4, res);
		}
	};
}

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

我想对大家说的话
《喜缺全书算法册》以原理、正确性证明、总结为主。
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1790247.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Nacos注册中心 --学习笔记

Nacos注册中心是什么&#xff1f; 想象一下一个繁忙的购物中心&#xff0c;里面有很多商店&#xff0c;每个商店都在某个位置提供不同的商品或服务。这个购物中心有一个信息台&#xff0c;人们可以在这里查询任何商店的位置和提供的服务。等到有新的商店开张&#xff0c;或者现…

运维工具 - SFTP 和 FTP 的区别?

SFTP 和 FTP 的区别有三点 连接方式 SFTP 是在客户端和服务器之间通过 SSH 协议建立的安全连接来传输文件&#xff0c;而 FTP 则是 TCP 端口 21 上的控制连接建立连接。 安全性 SFTP 使用加密传输认证信息来传输数据&#xff0c;因此 SFTP 相对于 FTP 更安全的。 效率 SF…

DevOps全面综述:从概念到实践

一、背景与概述 1.1 DevOps的起源与发展 DevOps&#xff08;Development and Operations的缩写&#xff09;是软件工程领域中的一种文化和实践方法&#xff0c;旨在促进开发团队与运维团队之间的协作&#xff0c;从而实现更高效、更可靠的软件交付。DevOps起源于敏捷软件开发方…

应届生毕业择业必看!这三个朝阳行业错过就晚了!2024普通人赚钱的行业、2024最适合创业的项目

俗话说“男怕入错行&#xff0c;女怕嫁错郎”。尤其是对于现在的年轻人来说&#xff0c;一个好的处于上升期的行业&#xff0c;所能带来的收益是无法估量的。所以在这个大学生即将步入社会的毕业季&#xff0c;我们一起看看国家统计局发布的这份数据报告&#xff0c;来分析哪些…

机器学习18个核心算法模型

1. 线性回归&#xff08;Linear Regression&#xff09; 用于建立自变量&#xff08;特征&#xff09;和因变量&#xff08;目标&#xff09;之间的线性关系。 核心公式&#xff1a; 简单线性回归的公式为&#xff1a; , 其中 是预测值&#xff0c; 是截距&#xff0c; 是斜…

动态规划——浅谈dp如何入门,以及入门题目(值得收藏,持续更新)

前言 动态规划如何入门?如果你问我怎么精通,那我只能告诉你我也不知道,但你要问我怎么入门,那我就可以和你说道说道了. 我并没有能力也不想说你看完就会了,我只是想给大家开个头,你只要知道怎么写了怎么去思考了,你就可以通过刷题来强化思维了,能走多远就看各位的造化了! 动…

【全开源】知识库文档系统(ThinkPHP+FastAdmin)

&#x1f4da;知识库文档系统&#xff1a;解锁知识的无限可能 一款基于ThinkPHPFastAdmin开发的知识库文档系统&#xff0c;可用于企业工作流程的文档管理&#xff0c;结构化记录沉淀高价值信息&#xff0c;形成完整的知识体系&#xff0c;能够轻松提升知识的流转和传播效率&a…

QT: 读写ini配置文件(实现qml界面登录,修改)

目录 一.功能介绍 二.暴露属性 三.指定INI文件的路径和格式。 四.登录操作 1.检查INI文件中是否含有登录信息&#xff1b; 2.读取存储的ID&#xff1b; 3.读取存储的密码; 4.成功返回1&#xff1b;失败返回2&#xff1b; 五.修改账号 1.检查INI文件中是否含有登录信…

C# Onnx E2Pose人体关键点检测

C# Onnx E2Pose人体关键点检测 目录 效果 模型信息 项目 代码 下载 效果 模型信息 Inputs ------------------------- name&#xff1a;inputimg tensor&#xff1a;Float[1, 3, 512, 512] --------------------------------------------------------------- Outputs ---…

pycharm链接auto al服务器

研0提前进组&#xff0c;最近阻力需求是把一个大模型复现&#xff0c;笔者电脑18年老机子&#xff0c;无法满足相应的需求。因此租用auto dl服务器。本文记录自己使用pycharm&#xff08;专业版&#xff09;链接auto dl期间踩过的坑。 1.下载pycharm专业版 这一步不解释了&am…

智慧启航 网联无限丨2024高通汽车技术与合作峰会美格智能分论坛隆重举行

5月30日下午&#xff0c;以“智慧启航 网联无限”为主题的2024高通汽车技术与合作峰会&美格智能分论坛在无锡国际会议中心隆重举行&#xff0c;本次论坛由高通技术公司与美格智能技术股份有限公司共同主办&#xff0c;上海市车联网协会、江苏省智能网联汽车产业创新联盟、江…

Android 如何保证开启debug模式之后再启动

很多时候会需要debug看Android启动时候的一些数据&#xff0c;但很多时候会存在自己开启debug后app已经过了自己要debug的那段代码的时机了。 那么怎么样可以保证一定能让启动后不会错过自己要debug的那段代码执行的时机呢&#xff1f; 可以用下面这行命令&#xff0c;其中co…

LabVIEW版本控制

LabVIEW作为一种流行的图形化编程环境&#xff0c;在软件开发中广泛应用。有效地管理版本控制对于确保软件的可靠性和可维护性至关重要。LabVIEW提供了多种方式来管理VI和应用程序的修订历史&#xff0c;以满足不同规模和复杂度的项目需求。 LabVIEW中的VI修订历史 LabVIEW内置…

遭遇Device Association Service占用CPU和内存过高异常

1.异常描述 在蓝牙设备搜索和配对过后&#xff0c;系统界面卡住了&#xff0c;查找了下任务管理器&#xff0c;发现有一个主机服务占用了过多的CPU和内存&#xff0c;且不断的在增长。截图如下&#xff1a; 百度查了下&#xff0c;Device Association Service是一个Win10系统服…

Oracle创建用户/表空间/赋权常规操作

1. 登录oracle su - oracle sqlplus / as sysdba 2.查看库里存在的用户,防止冲突 SELECT username FROM all_users ORDER BY username; 3.查看库里存在的表空间,防止冲突 select tablespace_name, file_id, file_name, round(bytes/(1024*1024),0) total_space_MB f…

像图一样交流:为大语言模型编码图

译者 | 高永祺 单位 | 东北大学自然语言处理实验室 原文链接&#xff1a;https://blog.research.google/2024/03/talk-like-graph-encoding-graphs-for.html 1.作者介绍 Bahare Fatemi&#xff0c;谷歌蒙特利尔研究部门的研究科学家&#xff0c;专门从事图表示学习和自然语言…

关于nginx的一些介绍

一、Nginx 简介 中文简介文档 二、Centos 安装 Nginx 2.1 安装编译工具及库文件 $ yum -y install make zlib zlib-devel gcc-c libtool openssl openssl-devel2.2 安装 pcre pcre 作用是 Nginx 支持 Rewrite 功能 $ cd /usr/local/src $ wget http://downloads.sourcef…

VUE3 学习笔记(12):对比Vuex与Pinia状态管理的基本理解

在组件传值中&#xff0c;当嵌套关系越来越复杂的时候必然会将混乱&#xff0c;是否可以把一些值存在一个公共位置&#xff0c;无须传值直接调用呢&#xff1f;VUEX应运而生&#xff0c;但是从VUE3开始对VUEX的支持就不那么高了&#xff0c;官方推荐使用Pinia。 Vuex配置 ST1:…

1.1 OpenCV随手简记(一)

OpenCV学习篇 OpenCV (Open Source Computer Vision Library) 是一个开源的计算机视觉库&#xff0c;它提供了大量的算法和函数&#xff0c;用于图像处理、计算机视觉和机器学习等领域。 1. OpenCV 简介 1.1 OpenCV 的起源和发展 OpenCV 项目始于 1999 年&#xff0c;由 In…

【C#学习笔记】属性和字段

文章目录 前言属性和字段的区别字段访问修饰符和关键字定义变量类型的定义变量命名变量的赋值 属性 不同的使用情况 前言 最近在工作的过程中常常会觉得自己在程序设计方面的能力还是有欠缺。例如一直对于变量的声明感到不足&#xff0c;在工作中为了图方便总是直接public定义…