仿LISP运算
题目描述:
LISP 语言唯一的语法就是括号要配对。
形如(OP P1 P2 …),括号内元素由单个空格分割。其中第一个元素 OP 为操作符
,后续元素均为其参数,参数个数取决于操作符类型。
注意:
参数 P1,P2 也有可能是另外一个嵌套的 (OP P1 P2 ...)
当前 OP 类型为 add / sub / mulQ / div (全小写),分别代表整数的加减乘除法简单起见,所有 OP 参数个数均为 2
输入输出描述:
输入描述:
输入一行LISP表达式,表达式中的操作数用空格相隔
输出描述:
LISP表达式的的结果
示例:
输入:
(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
解题思路1:
用栈来解题
:
遍历LISP表达式:
遇见左括号和空格跳过,遇见字符串(要么是操作符号、要么是参数)入栈
遇见右括号,说明匹配到一个嵌套最深的表达式
,弹出栈顶三个元素(依次是第二个操作数、第一个操作数,运算符号)进行运算,结算结果入栈。
最后栈中只有最终的结果
代码:
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String exp = scanner.nextLine();
// 使用栈来做
String s = stackParse(exp);
System.out.println(s);
}
/**
* 遇见左括号和空格跳过,遇见字符串(操作符号或者参数)入栈
* 遇见右括号,弹出栈顶三个元素进行运算,结果入栈。
* 最后栈中只有最终的结果
* @param remain
* @return
*/
private static String stackParse(String remain) {
Stack<String> stack = new Stack<>();
int pos = 0;
int length = remain.length();
while (pos < length) {
// 出现右括号,说明可以进行一次算术运算。
if (remain.charAt(pos) == ')') {
if (stack.size() == 1 && pos == length - 1) {
return stack.pop();
}
// 弹出参与运算的两个参数,计算结果入栈
int p2 = Integer.parseInt(stack.pop());
int p1 = Integer.parseInt(stack.pop());
String op = stack.pop();
switch (op) {
case "add":
stack.push((p1 + p2) + "");
break;
case "sub":
stack.push((p1 - p2) + "");
break;
case "mul":
stack.push((p1 * p2) + "");
break;
case "div":
// 除法运算时,除以 0,报错
if (p2 == 0) {
return "error!";
}
stack.push((p1 / p2) + "");
break;
default:
break;
}
pos++;
} else {
// 跳过空格和左括号
while (pos < length && (remain.charAt(pos) == ' ' || remain.charAt(pos) == '(')) {
pos++;
}
// 运算符、运算参数都入栈
int start = pos;
while (pos < length && remain.charAt(pos) != ' ' && remain.charAt(pos) != '(' && remain.charAt(pos) != ')') {
pos++;
}
stack.push(remain.substring(start, pos));
}
}
return stack.pop();
}
解题思路2:
用递归的方式来求解:
核心思想和用栈求解是一样的,先找出 嵌套最深的那个括号(嵌套最深的那个括号的位置:其左括号是最左边的那个左括号、其右括号是最左边的那个右括号)
,计算该括号的运算结果,然后将远算结果替代原括号表达式,继续求解剩余表达式中嵌套最深的那个括号…知道表达式中没有括号,只剩下最后的运算结果。
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String exp = scanner.nextLine();
// 每次循环的目标都是:计算表达式中嵌套最深的一层
while (exp.contains("(")) {
exp = parseBracket(exp);
if (exp.equals("error")) {
System.out.println(exp);
return;
}
// 此处可打印出剩余的未解析的表达式
//System.out.println(exp);
}
System.out.println(exp);
}
// 计算表达式中嵌套最深的括号,并重新组装计算后的表达式
private static String parseBracket(String remain) {
char[] chars = remain.toCharArray();
int leftParenthesis = 0;
int rightParenthesis = 0;
for (int i = 0; i < chars.length; i++) {
// 找到最右的左括号
if (chars[i] == '(') {
leftParenthesis = i;
}
// 找到最左的右括号
if (chars[i] == ')') {
rightParenthesis = i;
break;
}
}
// 截取出嵌套最深的括号内,进行计算
String substring1 = remain.substring(leftParenthesis + 1, rightParenthesis);
String[] s1 = substring1.split(" ");
String ope = s1[0];
int leftArg = Integer.parseInt(s1[1]);
int rightArg = Integer.parseInt(s1[2]);
String parenthesisRes = "";
switch (ope) {
case "add":
parenthesisRes = (leftArg + rightArg) + "";
break;
case "sub":
parenthesisRes = (leftArg - rightArg) + "";
break;
case "mul":
parenthesisRes = (leftArg * rightArg) + "";
break;
case "div":
if (rightArg == 0) {
return "error";
} else {
parenthesisRes = (leftArg / rightArg) + "";
}
break;
}
// 重新拼接括号
return remain.substring(0, leftParenthesis) + parenthesisRes + remain.substring(rightParenthesis + 1, remain.length());
}