【限时免费】20天拿下华为OD笔试之【栈】2023B-仿 LISP 运算【欧弟算法】全网注释最详细分类最全的华为OD真题题解

2023-11-10

【栈】2023B-仿 LISP 运算

题目描述与示例

题目描述

LISP 语言唯一的语法就是括号要配对。 形如 (OP P1 P2 …),括号内元素由单个空格分割。 其中第一个元素 OP 为操作符,后续元素均为其参数,参数个数取决于操作符类型

注意:参数 P1, P2 也有可能是另外一个嵌套的 (OP P1 P2 …) 当前 OP 类型为 add / sub / mul / div(全小写),分别代表整数的加减乘除法。简单起见,所有 OP 参数个数均为 2

举例:

  • 输入:(mul 3 -7) 输出: -21
  • 输入:(add 1 2) 输出:3
  • 输入:(sub(mul 2 4) (div 9 3)) 输出:5
  • 输入:(div 1 0) 输出:error

题目涉及数字均为整数,可能为负;不考虑 32 位溢出翻转,计算过程中也不会发生 32 位溢出翻转 除零错误时,输出 "error",除法遇除不尽,向下取整,即 3 / 2 = 1

输入

输入为长度不超过 512 的字符串,用例保证了无语法错误

输出

输出计算结果或者 "error"

示例一

输入

(div 12 (sub 45 45))

输出

error

示例二

输入

(add 1 (div -7 3))

输出

-2

解题思路

这道题也是经典的括号配对兼表达式求值的栈题,所给的字符串是一个前缀表达式

原字符串的处理

其难点主要在于对原字符串的处理,如何把字符串 s = (sub(mul 2 4) (div 9 3)),储存为方便栈运算的列表形式 ops = ['(', 'sub', '(', 'mul', '2', '4', ')', '(', 'div', '9', '3', ')', ')']

对于这个问题。这里提出两种可能的处理方式。

  1. 使用字符串的 replace() 方法,将 s 中所有的左括号 "(" 和右括号 ")" 前后都加上空格,即替换为 " ( "" ) ",然后再对替换后的字符串 s 使用 split() 方法。代码为
s = input()
s = s.replace("(", " ( ")
s = s.replace(")", " ) ")
ops = s.split()
  1. while 循环遍历原字符串 s,初始化索引 i = 0。如果 ch = s[i] 为:
    • 数字或负号 "-"。说明此时正在遍历一个数字,将 ch 添加到列表最后一个元素的尾部 ops[-1] 即可,即一个数字进行延申操作。同时索引 i += 1
    • 字母。说明遇到四种操作符中的一种。只需要记录操作符首字母即可,将首字母字符 ch 加入 ops 列表尾部,同时索引 i += 3
    • 括号。将括号字符 ch 加入 ops 列表尾部,同时索引 i += 1
    • 空格,说明接下来可能要遇到数字,将一个空字符串 "" 加入 ops 列表尾部,用于记录接下来可能出现的数字,同时索引 i += 1

上述逻辑整理为代码即

s = input()
ops = list()
# 初始化遍历字符串s的索引i = 0
i = 0
n = len(s)
# 先将字符串s转化为一个方便进行遍历的数组
while i < n:
    ch = s[i]
    # ch是数字或者负号"-"的情况,添加到列表最后一个元素的尾部即可,即一个数字进行延申操作
    if ch.isdigit() or ch == "-":
        # 往栈顶的数字+1
        ops[-1] += ch
        i += 1
    # ch是括号、操作符或空格的情况
    else:
        # 遇到字母,是一个操作符,记录操作符首字母即可,首字母字符加入ops列表尾部,索引i前进3格
        if ch.isalpha():
            ops.append(ch)
            i += 3
        # 遇到括号,括号字符字符加入ops列表尾部,索引i前进1格
        if ch == "(" or ch == ")":
            ops.append(ch)
            i += 1
        # 遇到空格,说明接下来可能要遇到数字,将一个空字符串加入ops列表尾部,用于记录数字,
        # 索引i前进1格
        else:
            ops.append("")
            i += 1

栈辅助前缀表达式求值

在获得了 ops 列表之后,剩下的部分就是常规的栈操作了。首先需要构建一个空栈 stack,然后遍历 ops 中的所有符号 ch。当 ch

  • 左括号或字母,ch 入栈。

  • 数字,转为整数后,即 int(ch) 入栈。

  • 右括号,进行出栈和计算。由于是前缀表达式,因此分别弹出两次栈顶元素,得到 num1num2,然后再次弹出栈顶元素得到用字母表示的操作符 op,然后再一次弹出栈顶元素,把该右括号对应的左括号 "(" 出栈。

    • 根据 op 的取值,对 num1num2 进行加减乘除的操作,并且需要把计算的结果 res 再次存入栈中。
    • 这里要注意除法操作可能会出现除 0 的情况,如果出现了则需要进行异常处理。

上述逻辑整理为代码即

for ch in ops:
    if ch == "(" or ch.isalpha():
        stack.append(ch)
    elif ch == ")":
        num2 = stack.pop()
        num1 = stack.pop()
        op = stack.pop()[0]
        stack.pop()
        if op == "a":
            res = num1 + num2
        elif op == "s":
            res = num1 - num2
        elif op == "m":
            res = num1 * num2
        elif op == "d":
            if num2 == 0:
                isError = True
                break
            res = floor(num1 / num2)
        stack.append(res)
    else:
        stack.append(int(ch))

代码

# 题目:2023B-仿LISP运算
# 分值:200
# 作者:闭着眼睛学数理化
# 算法:栈
# 代码看不懂的地方,请直接在群上提问

from math import floor

# 处理字符串的方式取第一种做法
s = input()
s = s.replace("(", " ( ")
s = s.replace(")", " ) ")
ops = s.split()

# 初始化空栈
stack = list()
# 初始化一个错误标记
isError = False

# 遍历ops中的所有符号
for ch in ops:
    # 遇到左括号和字母操作符
    # 入栈
    if ch == "(" or ch.isalpha():
        stack.append(ch)
    # 遇到右括号,出栈
    elif ch == ")":
        num2 = stack.pop()
        num1 = stack.pop()
        # 弹出操作符,只获得其首字母即可
        op = stack.pop()[0]
        # 弹出左括号
        stack.pop()
        # 加法操作
        if op == "a":
            res = num1 + num2
        # 减法操作
        elif op == "s":
            res = num1 - num2
        # 乘法操作
        elif op == "m":
            res = num1 * num2
        # 除法操作
        elif op == "d":
            # 出现除0的错误
            if num2 == 0:
                isError = True
                break
            res = floor(num1 / num2)
        stack.append(res)
    # 遇到数字,转为int后入栈
    else:
        stack.append(int(ch))


if isError:
    print("Error")
else:
    print(stack[0])

时空复杂度

时间复杂度:O(N)。仅需一次遍历数组,每一个字符最多出入栈各一次。

空间复杂度:O(N)。栈所占用的额外空间。

华为OD算法冲刺训练

  • 华为OD算法冲刺训练目前开始常态化报名!目前已服务100+同学成功上岸!

  • 课程讲师为全网50w+粉丝编程博主@吴师兄学算法 以及小红书头部编程博主@闭着眼睛学数理化

  • 每期人数维持在20人内,保证能够最大限度地满足到每一个同学的需求,达到和1v1同样的学习效果!

  • 30+天陪伴式学习,20+直播课时,300+动画图解视频,200+LeetCode经典题,100+华为OD真题,还有简历修改与模拟面试将为你解锁

  • 可查看链接 OD算法冲刺训练课程表 & OD真题汇总(持续更新)

  • 绿色聊天软件戳 sheepvipvip了解更多

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【限时免费】20天拿下华为OD笔试之【栈】2023B-仿 LISP 运算【欧弟算法】全网注释最详细分类最全的华为OD真题题解 的相关文章

  • 合并 2 个排序列表

    我被要求针对以下问题提出尽可能多的解决方案 编写一个函数 它接受两个数字列表 均假设为 按升序排列 并将它们合并到一个列表中 也在 升序 我的第一个解决方案是append list1 onto list2然后重新sort 然后我发现一个内置
  • (撰写)Common Lisp

    我们在 P Graham 的 ANSI Common Lisp 第 110 页 中找到了这个函数构建器来实现组合 参数是 n gt 0 带引号的函数名称 我不完全理解它 所以我将在这里引用代码并在下面指出我的问题 defun compose
  • 刚习惯在 OS X 上的 emacs 中进行 paredit - 为什么 C-) 不起作用?

    我最近在 Mac OS X Leopard 中设置了 Common Lisp 编程环境 我发现 paredit 是一个不可或缺的 emacs 模块 Paredit 正在尽力帮助我更轻松地处理我的 Lisp 代码 但我遇到了一些陷阱 C 必然
  • 返回总和的 Lisp 函数

    我正在尝试编写一个奇怪的函数 所以请耐心等待 这个函数应该有一个列表L作为参数并有一个sum多变的 如果L不是列表 它应该返回nil 否则 它应该迭代列表的每个元素并执行以下操作 如果元素是数字且小于零 则应从总和中减去 1 如果元素是数字
  • 更改列表的第 n 个元素

    我想更改列表的第 n 个元素并返回一个新列表 我想到了三个相当不优雅的解决方案 defun set nth1 list n value let list2 copy seq list setf elt list2 n value list2
  • 在lisp中,如何使用floor函数返回的第二个值?

    当我这样做时 4楼3 我得到了 1 1 3 但我该如何使用这 1 3 呢 例如 您可以使用将其绑定到变量multiple value bind multiple value bind quot rem floor 4 3 format t
  • Scheme/Racket有枚举操作吗?

    Scheme Racket 是否有相当于 Haskell 中的 a b 表示法的枚举表示法 在 Haskell 中 1 5 计算结果为列表 1 2 3 4 5 for list i in range 1 6 i sequence gt li
  • Common Lisp 中的 LET 与 LET*

    我理解 LET 和 LET 并行绑定与顺序绑定 之间的区别 并且作为理论上的问题 它非常有意义 但有没有什么情况你曾经真正需要过 LET 在我最近查看的所有 Lisp 代码中 您可以将每个 LET 替换为 LET 而无需进行任何更改 编辑
  • 以下函数式编程模式的正确术语是什么?

    我听说它被称为stream http mitpress mit edu sicp full text sicp book node72 html as an 无限列表 http en wikibooks org wiki Clojure P
  • 查找 lambda 表达式中的自由变量

    有谁知道如何找出 lambda 表达式中的自由变量 自由变量是不属于 lambda 参数的变量 我当前的方法 这对我毫无帮助 是简单地使用 car 和 cdr 来遍历表达式 我的主要问题是确定一个值是否是一个变量或者它是否是方案原语之一 有
  • 在 Lisp 解释过程中,“读者”的任务是什么?

    我想知道 读者 在解释 编译 Lisp 程序期间的目的 或者更准确地说 是 读者 的任务 从我刚刚完成的问题前研究来看 在我看来 读者 特别是本例中的 Clojure 可以被视为 语法预处理器 它的主要职责是读取器宏和原始形式的扩展 所以
  • 将列表传播到父代 sexp 中

    在任何 lisp 中是否有一种形式可以在父 sexp 中 传播 列表 喜欢 spread 1 2 3 gt 1 2 3 有两种方法可以做到这一点 哪个更好取决于您最终想要什么 一般来说 您可以使用 inside 反引号 表格如下 被评估以生
  • 对于案例,这些表达案例的方法中哪种最好?

    这些都有效 defun testcaseexpr thecase case thecase foo format t matched foo bar format t matched bar funk format t matched fu
  • 使用包阴影符号

    例如 我有这个包定义 它遮蔽了 COMMON LISP LISTEN defpackage shadows use common lisp shadow listen export listen 然后我想使用另一个包中的这个包 比如说 de
  • Lisp 中的 (定义 (平均 ....))

    我只是在玩scheme lisp 并正在考虑如何纠正我自己的定义average 我不确定如何做一些我认为需要的事情 定义一个接受任意数量参数的过程 计算这些参数 将参数列表传递给 以将它们加在一起 有人有定义的例子吗average 我似乎对
  • (cons 'a (cons 'b 'c)) 和 (cons 'a '(b.c)) 之间的 Lisp 区别

    有什么区别 cons a cons b c A B C and cons a b c A B C 我需要使用 cons 创建以下列表 a b c 所以我试图理解 是什么 代表 L E 我有以下内容 cons cons a b c 但它产生
  • 为什么在 emacs-lisp 中的函数参数之前使用#'?

    我熟悉 Emacs Lisp 但不熟悉 Common 或任何其他 Lisp 一些 Lisp 程序员建议 例如emacs 的基本功能 https stackoverflow com questions 17076646 a basic fun
  • 为什么 SBCL eval 函数会丢失它运行的宏?

    print x 打印出我想要评估的内容 但是 eval x 失败了 但如果我运行 x 它就可以了 我缺少什么 请告诉我为什么这不起作用 或者我是否在做一些愚蠢的事情 我正在尝试打印动态大小的表并设置 lambda 变量以最终计算表中每个单元
  • 递归分割列表函数 LISP

    split list 函数接受一个列表并返回一个由两个列表组成的列表 其中两个列表由输入的交替元素组成 我写了以下内容 defun split list L cond endp L list NIL NIL t let X split li
  • Scheme (Lisp) 中树的深度反转

    我对Scheme中的基本树数据结构进行了深度逆向 define deep reverse t cond null t not pair t t else cons deep reverse cdr t deep reverse car t

随机推荐

  • python-运算符

    除 x除以一 注意整数相除得到的是整数 如4 3结果为1 4 0 3或者4 3 0结果为1 3333333 取整除 返回商的整数 4 3 0的结果为1 0 取模 返回除法的余数 8 3得到2
  • 力扣 214. 最短回文串 一遍过,很舒服(代码做了分层,很容易理解)

    include
  • leecode344反转字符串(附有调试代码)

    package heima study day3 import java util Scanner public class 反转字符串344 public static void main String args Scanner inpu
  • 为什么要使用ConstraintLayout?

    本文为博主原创文章 转载请注明出处 http blog csdn net jingsummer article details 78615360 源码地址 ConstraintLayoutDemo 相信大家对ConstraintLayout
  • Java 设计模式(十二):享元模式

    享元模式 GitHub 地址 https github com yifanzheng java design patterns 享元模式 Flyweight Design Pattern 顾名思义就是共享单元 享元模式的意图是复用对象 节省
  • STM32的独立看门狗

    独立看门狗时钟频率一般以40KHz 但不是非常准确 变化范围在15 47KHz 看门狗在开启后不能关闭 除非复位 1 寄存器 关键字寄存器 IWDG KR 用来写指令 指令有0xAAAA 把IWDG RLR的值载入到计数器 避免 产生复位
  • [BAPI]外向交货单按批次拆分[BAPI_OUTB_DELIVERY_CHANGE]

    下面介绍SAP SD的销售订单外向交货单按批次拆分 Batch Managed 包括前台操作和调用bapi BAPI OUTB DELIVERY CHANGE 实现 1 前台操作 按批次拆分操作 外向交货单Tcode VL02n amp l
  • Java final 详解

    一 final 基础使用 1 1 修饰类 当某个类的整体定义为 final 时 就表明了你不能打算继承该类 而且也不允许别人这么做 即这个类是不能有子类的 注意 final 类中的所有方法都隐式为 final 因为无法覆盖他们 所以在 fi
  • 泛型中K TVE? Object等分别代表什么含义。

    E一Element 在集合中使用 因为集合中存放的是元素 T Type Java类 K Key 键 V Value 值 N Number 数值类型 表示不确定的java类型 无限制通配符类型 S U V 2nd 3rd 4th types
  • ArcGIS API 4.x for Js 点击地图获取经纬度

    需求 鼠标点击地图后获取当前的经纬度 效果 需添加API esri geometry support webMercatorUtils 代码 view on click function e geom webMercatorUtils xy
  • 规范的建表语句

    CREATE TABLE student info id INT NOT NULL AUTO INCREMENT COMMENT 主键 stu name VARCHAR 10 NOT NULL DEFAULT COMMENT 姓名 stu
  • Python基础语法入门(第十五天)——装饰器传参与匿名函数

    在上篇文章中留下了一个问题 装饰器的传参如何实现 其实对于这个问题来说 首先要搞清楚传参的顺序是什么 我们已知的是装饰器的本质就是函数 那么在这嵌套了多层的函数中每一个函数接收的参数是哪一个 作用域哪个范围 这就是实现装饰器传参前需要解决的
  • IDEA+Maven创建javaweb项目out.print()报错

    IDEA Maven创建javaweb项目out print 报错 从原型中创建如图所示 注意不要选错 选好项目目录设置好项目名称之后下一步 注意这个地方的Maven路径 用户设置文件 本地仓库要选择自己的 不要使用IDEA自带的MAven
  • Sqlite3简介

    SQLite3 简介 SQLite3 是一种轻量级的嵌入式数据库引擎 被广泛应用于各种应用程序中 包括移动设备 桌面应用程序和嵌入式系统 它以其简单 高效和零配置的特点而受到开发者的喜爱 以下是 SQLite3 的一些重要特点 嵌入式数据库
  • Android手机9008模式刷机教程(以小米手机为例)

    机型 红米1s电信版2013028 故障 一开始可以进入fastboot 后来无法进入fastboot 无限重启 后来开机键无反应 大家都知道 刷机的方式有很多种 大体来讲 我们刷机一般采用以下几种方式 1 卡刷 即进入recovery模式
  • 理解golang调度

    线程模型 在细说 Go 的调度模型之前 先来说说一般意义的线程模型 线程模型一般分三种 由用户级线程和 OS 线程的不同对应关系决定的 N 1 即全部用户线程都映射到一个OS线程上 上下文切换成本最低 但无法利用多核资源 1 1 一个用户线
  • 真香!Jenkins 主从模式解决问题So Easy~

    01 Jenkins 能干什么 Jenkins 是一个开源软件项目 是基于 Java 开发的一种持续集成工具 用于监控持续重复的工作 旨在提供一个开放易用的软件平台 使软件项目可以进行持续集成 中文官网 https jenkins io z
  • 二级教程python语言程序设计答案_全国计算机等级考试二级教程-Python语言程序设计(2018年版)编程题-参考答案......

    习题3 基本数据类型 1 获得用户输入的一个整数 输出该整数百位及以上的数字 i input 请输入一个整数 print i 2 复制代码 2 获得用户输入的一个字符串 将字符串按照空格分割 然后逐行打印出来 i input 请输入一个带空
  • unbuntn X64 安装vsftpd

    Fortunately the good folks at The Fronteer Group have backported vsftp until the full release of ver 3 of vsftp comes ou
  • 【限时免费】20天拿下华为OD笔试之【栈】2023B-仿 LISP 运算【欧弟算法】全网注释最详细分类最全的华为OD真题题解

    栈 2023B 仿 LISP 运算 题目描述与示例 题目描述 LISP 语言唯一的语法就是括号要配对 形如 OP P1 P2 括号内元素由单个空格分割 其中第一个元素 OP 为操作符 后续元素均为其参数 参数个数取决于操作符类型 注意 参数