表达式
【问题描述】
明明进了中学之后,学到了代数表达式。有一天,他碰到一个很麻烦的选择题。这个题目的题干中首先给出了一个代数表达式,然后列出了若干选项,每个选项也是一个代数表达式,题目的要求是判断选项中哪些代数表达式是和题干中的表达式等价的。
这个题目手算很麻烦,因为明明对计算机编程很感兴趣,所以他想是不是可以用计算机来解决这个问题。假设你是明明,能完成这个任务吗?
这个选择题中的每个表达式都满足下面的性质:
1. 表达式只可能包含一个变量‘a’。
2. 表达式中出现的数都是正整数,而且都小于10000。
3. 表达式中可以包括四种运算‘+’(加),‘-’(减),‘*’(乘),‘^’(乘幂),以及小括号‘(’,‘)’。小括号的优先级最高,其次是‘^’,然后是‘*’,最后是‘+’和‘-’。‘+’和‘-’的优先级是相同的。相同优先级的运算从左到右进行。(注意:运算符‘+’,‘-’,‘*’,‘^’以及小括号‘(’,‘)’都是英文字符)
4. 幂指数只可能是1到10之间的正整数(包括1和10)。
5. 表达式内部,头部或者尾部都可能有一些多余的空格。
下面是一些合理的表达式的例子:
((a^1) ^ 2)^3,a*a+a-a,((a+a)),9999+(a-a)*a,1 + (a -1)^3,1^10^9……
【输入描述】
计算表达式以及候选表达式,候选表达式规模n,2<= n<=26,每个表达式对应一个顺序的英文字母,需要自行计算。
【输出描述】
等价表达式的序号,所有候选表达式序号从A、B、C依次排列
【样例输入】
( a + 1) ^2
3
(a-1)^2+4*a
a + 1+ a
a^2 + 2 * a * 1 + 1^2 + 10 -10 +a –a
【样例输出】
AC
【数据规模】
对于30%的数据,表达式中只可能出现两种运算符‘+’和‘-’;
对于其它的数据,四种运算符‘+’,‘-’,‘*’,‘^’在表达式中都可能出现。
对于全部的数据,表达式中都可能出现小括号‘(’和‘)’。
【解决思路】
1、 按照常规表达式的做法,我们需要创建两个堆栈values和opeartion,分别存储数字与计算符。
2、 对于数字,我们只需要添加到对应的values堆栈中即可,因为它是被动接受计算的,而非能主动发起计算。
3、 对于符号符,我们需要从以下几个方面考虑:
a) 当operation为空时,直接添加对应计算符;
b) 当前计算符大于已经添加的计算符,则直接将其添加到operation中;
c) 当前计算符不大于已经添加的计算符时,需要对已经添加的高优先级运算符进行计算,直到operation为空,或者当前计算符大于已经添加的计算符为止;
d) 对于’(‘,当其需要作为被添加项时,其计算优先级应该是最高,当其作为栈顶计算符输出时,其计算优先级应该降到最低,否则违背了(c),会直接计算’(‘,导致错误。
e) 当’(‘遇到’)’时,则应将’(‘从operation中pop出。
代码:
package test; import java.util.Stack; public class Test { private static Integer a = 3; public static void main(String[] args) { String mainExpression = "( a + 1) ^2"; String candidateExpression[] = { "(a-1)^2+4*a", "a + 1+ a", "a^2 + 2 * a * 1 + 1^2 + 10 -10 +a -a" }; System.out .println(getComputeResult(mainExpression, candidateExpression)); } public static String getComputeResult(String mainExpression, String[] candidateExpression) { long result = compute1(mainExpression.replace(" ", ""), a); StringBuilder sb = new StringBuilder(); for (int i = 0; i < candidateExpression.length; i++) { if (result == compute1(candidateExpression[i].replace(" ", ""), a)) { sb.append((char) ('A' + i)); } } return sb.toString(); } public static long compute1(String expression, int a) { expression = expression.replace(" ", ""); Stack<Long> values = new Stack<Long>(); Stack<String> operation = new Stack<String>(); // 通过正则来识别出,当前每个数字或者计算符 Pattern pattern = Pattern.compile("\\D|\\d+"); Matcher matcher = pattern.matcher(expression); while (matcher.find()) { String str = matcher.group(); // 数字,直接添加到values中,等待计算 if (str.matches("a|\\d+")) { values.push(str.equals("a") ? a : Long.parseLong(str)); } else { computvalue(values, operation, str); } } // 计算完成后,仍有未被计算的,则直接计算即可。 while (!operation.isEmpty()) { long right = values.pop(); long left = values.pop(); String oper = operation.pop(); long result = calculate(oper, left, right); values.push(result); } return values.pop(); } private static void computvalue(Stack<Long> values, Stack<String> operation, String str) { if (operation.isEmpty()) { operation.push(str); } else { int newOper = grade_oper(str); int topOper = grade_oper(operation.lastElement()); topOper = topOper == 8 ? 0 : topOper;// 对于左括号,如果已经添加进去了。则其优先级应该降到最低,否则,会导致后续的计算符无法进行正常计算 // 如果是左括号,直接抛掉 if (topOper == 0 && newOper == 0) { operation.pop(); return; } // 当前计算符号计算等级大于已经添加的计算等级,则直接添加,否则进行计算 if (topOper < newOper) { operation.push(str); } else { long right = values.pop(); long left = values.pop(); String oper = operation.pop(); long result = calculate(oper, left, right); values.push(result); // 继续判断当前计算符,是否依然小于已经存储的计算符号 computvalue(values, operation, str); } } } public static int grade_oper(String oper) { if (oper.equals("(")) { return 8; } else if (oper.equals(")")) { return 0; } else if (oper.equals("^")) { return 6; } else if (oper.equals("*")) { return 3; } else { return 1; } } private static Long calculate(String mask, Long lm, Long rm) { if ("+".equals(mask)) { return lm + rm; } else if ("-".equals(mask)) { return lm - rm; } else if ("*".equals(mask)) { return lm * rm; } else if ("^".equals(mask)) { return pow(lm, rm); } return 0L; } private static Long pow(Long a, Long b) { if (a == 1) return 1L; else if (b == 1) return a; else return pow(a, b - 1) * a; } }