仿LISP运算_200分_A/B复用题_递归/字符串解析

仿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());
}

字符串递归解析相关题目

报文解压缩_200分_B卷_递归

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值