华为笔试题--LISP括号匹配 解析及源码实现
在17年校招中3道题目AC却无缘华为面试,大概是华为和东华互不待见吧!分享一道华为笔试原题,共同进步!
***************************************************************************************************************************************************************************
题目描述:
LISP语言唯一的语法就是括号要匹配。
形如(OP P1 P2 …),括号内元素由单个空格分割。
其中第一个元素OP为操作符,后续元素均为其参数,参数个数取决于操作符类型
注意:参数P1,P2也有可能是另外一个嵌套的(OP P1 P2 …)
其中OP类型为add/sub/mul/div(全小写),分别代表整数的加减乘除法
其中add/mul参数个数2或以上,sub/div参数个数为2
举例:
-输入:(mul 3 -7) 输出:-21
-输入:(add1 2 3) 输出:6
-输入:(sub (mul 2 4) (div 9 3)) 输出:5
-输入:(div 1 0) 输出:error
题目涉及数字均为整数,可能为负;不考虑32位溢出翻转
除零错误时,输出"error",除法遇除不尽,取整,即3/2=1
输入描述:
合法C字符串,字符串长度不超过512;用例保证了无语法错误
输出描述:
合法C字符串,字符包括'0'-'9'及负号'-'或者'error'
示例
输入 (add 1 2 3) 输出 6
*********************************************************
这是数据结构中括号匹配问题的变形。在检验括号是否匹配的方法中,可用“期待的急迫程度”这个概念来描述。在算法中设置了一个栈,每读入一个括号,若是右括号,则或者使置于栈顶的最急迫的期待得以消解,或者是不合法的情况;若是左括号,则作为一个新的更急迫的期待压入栈中,自然使原有的在栈中的所有未消解的期待的急迫性降了一级。另外,在算法的开始和结束时,栈都应该是空的。
同样的道理,针对LISP的括号匹配,我们不仅需要一个符号栈opstack去保存每一个括号里的操作符OP,还需要一个栈strstack去保存括号里的参数P1、P2及符号位。
从头到尾对输入的C字符串进行遍历,当遇到左括号"("时,将"("压入strstack中,其后的操作符压入opstack栈中;当遇到参数P时,通过字符串分割,放入strstack中;当遇到右括号")"时,在strstack栈中依次弹出参数,压入tmps栈,直到遇到"("为止,那么tmps中为一个不包含子括号参数列表,运算符为opstack的栈顶元素,其中根据操作符和参数可以进行加减乘除运运算,这部分不讨论。注意,运算结果需要在压入strstack栈中作为参数P。
如下图所示,以(sub (mul 2 4) (div 9 3))为例,在遇到第一个")"时,strstack中分别为{(,(,2,4},opstack中分别为{sub ,mul},则strstack中依次弹出4,2,(,运算符为opstack的栈顶元素mul,可以得到结果为8,其中运算结果再压入strstack中作为参数。

程序输入输出,运行结果示意图:

源码分享:
代码同步更新于 https://github.com/wylloong/TinyPrograms/blob/master/Coding%20Interviews/LISPGenerateParentheses.cpp
#include <iostream>
#include <algorithm>
#include <string>
#include <stack>
#include <vector>
#include <cstdio>
#include <stdlib.h>
#include <cstring> using namespace std; int main()
{
char chs[];
bool error = false;
gets_s(chs);
//gets(chs); //old version
std::string str(chs);
std::stack<std::string> opstack; // operations
std::stack<std::string> strstack; // divided strings
for (int i = ; i < str.size();)
{
if (str[i] == ' ')
{
i = i + ;
continue;
}
if (str[i] == '(')
{
strstack.push(std::string("("));
int spaceIndex = str.find(' ', i);
std::string tmp = str.substr(i + , spaceIndex - i - );
opstack.push(tmp); // operation
i = spaceIndex;
}
else if (str[i] == ')')
{
std::string curOp = opstack.top();
opstack.pop();
std::vector<std::string> tmps; // strs temp
while (strstack.top() != "(")
{
tmps.push_back(strstack.top());
strstack.pop();
}
strstack.pop();
// add
if (curOp == "add")
{
int temp = ;
for (int i = ; i<=tmps.size() - ; ++i)
{
temp += atoi(tmps[i].c_str());
}
strstack.push(to_string(temp));
}
// sub
else if (curOp == "sub")
{
int temp = ;
if (tmps.size() > )
temp = atoi(tmps[tmps.size() - ].c_str());
for (int i = tmps.size() - ; i >= ; --i)
{
temp -= atoi(tmps[i].c_str());
}
strstack.push(to_string(temp));
}
// mul
else if (curOp == "mul")
{
int temp = ;
if (tmps.size() > )
temp = atoi(tmps[tmps.size() - ].c_str());
for (int i = tmps.size() - ; i >= ; --i)
{
temp *= atoi(tmps[i].c_str());
}
strstack.push(to_string(temp));
}
// div
else if (curOp == "div")
{
int temp = ;
if (tmps.size() > )
temp = atoi(tmps[tmps.size() - ].c_str());
for (int i = tmps.size() - ; i >= ; --i)
{
int data1 = atoi(tmps[i].c_str());
if (data1 == )
{
error = true;
break;
}
else
temp /= data1;
}
if (error)
break;
else
strstack.push(to_string(temp));
}
++i;
}
else // substrs
{
// get substring by ' ' or ')'
auto index = str.find(' ', i);
auto index2= str.find(')', i);
if (index < index2)
{
strstack.push(str.substr(i, index - i));
i = index;
}
else
{
strstack.push(str.substr(i, index2 - i));
i = index2;
}
}
}
if (error)
cout << "error";
else
cout << atoi(strstack.top().c_str());
return ;
}
华为笔试题--LISP括号匹配 解析及源码实现的更多相关文章
- [算法2-数组与字符串的查找与匹配] (.NET源码学习)
[算法2-数组与字符串的查找与匹配] (.NET源码学习) 关键词:1. 数组查找(算法) 2. 字符串查找(算法) 3. C#中的String(源码) 4. 特性Attribute 与内 ...
- mvc5 解析route源码实现自己的route系统
Asp.net mvc5 解析route源码实现自己的route系统 url route 路由系统的责任是找到匹配的路由,创建路由数据,并将请求分配给一个处理程序. 选择动作是 MVC 的处理程序 ...
- 浩哥解析MyBatis源码(十)——Type类型模块之类型处理器
原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6715063.html 1.回顾 之前的两篇分别解析了类型别名注册器和类型处理器注册器,此二 ...
- 解析 ViewTreeObserver 源码(下)
继上篇内容,本文介绍 ViewTreeObserver 的使用,以及体会其所涉及的观察者模式,期间会附带回顾一些基础知识.最后,我们简单聊一下 Android 的消息传递,附高清示意图,轻松捋清整个传 ...
- Jsoup解析网页源码时常用的Element(s)类
Jsoup解析网页源码时常用的Element(s)类 一.简介 该类是Node的直接子类,同样实现了可克隆接口.类声明:public class Element extends Node 它表示由一个 ...
- 用Beautiful Soup解析html源码
#xiaodeng #python3 #用Beautiful Soup解析html源码 html_doc = """ <html> <head> ...
- Python解析器源码加密系列之(二):一次使用标准c的FILE*访问内存块的尝试
摘要:由于近期打算修改Python解释器以实现pyc文件的加密/解密,出于保密的要求,解密之后的数据只能放在内存中,不能写入到文件中.但是后续的解析pyc文件的代码又只能接受FILE*作为入参,所以就 ...
- HtmlAgilityPack --解析Html源码
最近项目需要从网络上抓取一下数据解析Html源码,奈何正则表达式难写,于是网上搜索找到了“ HtmlAgilityPack”类库,敏捷开发,果然效率非同寻常. 在此做笔记,写下心得,顺便给自己总结一下 ...
- 二十三、并发编程之深入解析Condition源码
二十三.并发编程之深入解析Condition源码 一.Condition简介 1.Object的wait和notify/notifyAll方法与Condition区别 任何一个java对象都继承于 ...
随机推荐
- 201521123114 《Java程序设计》第3周学习总结
1. 本章学习总结 2. 书面作业 Q1.代码阅读 以上代码可否编译通过?哪里会出错?为什么?尝试改正? 如果创建3个Test1对象,有内存中有几个i,几个j?请分析原因? 不能编译通过,Test1g ...
- 201521123105 第三周Java学习总结
1. 本周学习总结 对象(实际个体) 对象与类 类(模板) 2.书面作业 1.代码阅读 public class Test1 { private int i = 1;//这行不能修改 private ...
- 201521123055 《Java程序设计》第2周学习总结
1. 本章学习总结 (1)认识PATH和CLASSPATH (2)SET PATH/CLASSPATH和-cp的用法 (3)了解BigDecimal.BigInteger.ArrayList/Lis ...
- 201521123035《Java程序设计》第一周学习总结
1.本周学习总结 本周学习了Java从诞生到如今的部分历史,并通过了老师的课堂演示了解了Java在cmd中的编译过程.然后还学习了JDK,JRE,JVM. 2. 书面作业 1.为什么java程序可以 ...
- VBScript中Msgbox函数的用法
MsgBox(prompt[, buttons][, title][, helpfile, context]) [用途]:弹出对话框,并获取用户的操作结果. [参数说明]: propmt:对话框中展示 ...
- 201521123063 《Java程序设计》 第14周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图.Onenote或其他)归纳总结多数据库相关内容. 2. 书面作业 1. MySQL数据库基本操作 1.1 建立数据库test.表students. ...
- 201521123030 《Java程序设计》 第14周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多数据库相关内容. 2. 书面作业 1. MySQL数据库基本操作 建立数据库,将自己的姓名.学号作为一条记录插入.(截图,需出现自 ...
- Markdown 模板
一个例子: 例子开始 1. 本章学习总结 今天主要学习了三个知识点 封装 继承 多态 2. 书面作业 Q1. java HelloWorld命令中,HelloWorld这个参数是什么含义? 今天学了一 ...
- java web:在eclipse中如何创建java web 项目
Eclipse创建java web工程 eclipse版本:eclipse-jee-4.5-win32-x64 tomcat版本:apache-tomcat-7.0.63-windows-x64 jd ...
- 微信小程序购物车产品计价
微信小程序购物车产品计价: 问题:当选中商品,价格累加时会出现无限循环小数 解答:在计算前先parseFloat(变量),再计算的最后使用(变量).toFixed(2)保留两位小数 例如: jiaCa ...