题解 | #表达式求值#
表达式求值
https://www.nowcoder.com/practice/9566499a2e1546c0a257e885dfdbf30d
import java.util.Scanner; import java.util.Stack; // 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); while (in.hasNextLine()) { String str = in.nextLine(); StringBuffer sbf = new StringBuffer(str); char[] cs = str.toCharArray(); int flag = 0; while (flag >= 0) { int start = 0; int end = cs.length; for (int i = 0; i < cs.length; i++) { if (cs[i] == '(') { start = i; flag++; } } for (int i = 0; i < cs.length; i++) { if (cs[i] == ')' && i > start) { end = i; break; } } // System.out.println("start = " + start + "end = " + end); StringBuilder sbu = new StringBuilder(); // 将'('与')'中间的值提取出来计算 if (flag > 0) { for (int i = start+1; i < end; i++) { sbu.append(cs[i]); } flag -= 2; } else if (flag == 0) { flag -= 1; for (int i = 0; i < cs.length; i++) { sbu.append(cs[i]); } break; } // System.out.println("exp : " + sbu.toString()); String res = compute(sbu.toString()); //将计算结果字符串替换本来的字符串 sbf.replace(start, end+1, res); cs = sbf.toString().toCharArray(); // System.out.println(flag); // 继续循环 } String result = compute(sbf.toString()); System.out.println(result); } in.close(); } // 按照优先级计算算术式 // 此算术式为最简单的+、-、*、/运算式 static String compute(String exp) { // System.out.println("exp:" + exp); Stack<Character> cStack = new Stack<>(); Stack<Integer> numStack = new Stack<>(); StringBuilder sbu = new StringBuilder(); int result = 0; char[] cs = exp.toCharArray(); for (char c : cs) { if (c == '*' || c == '/' || c == '+' || c == '-') { if (!sbu.toString().equals("")) { int num = Integer.parseInt(sbu.toString()); numStack.push(num); // System.out.println("pushed num = " + num); if (!cStack.isEmpty()) { char com = cStack.pop(); // System.out.println("got compute :" + com); if (com == '*') { int num2 = numStack.pop(); int num1 = numStack.pop(); // System.out.println("num1 :" + num1); // System.out.println("num2 :" + num2); numStack.push(num1 * num2); // System.out.println("pushed * num = " + num1 * num2); } else if (com == '/') { int num2 = numStack.pop(); int num1 = numStack.pop(); // System.out.println("num1 :" + num1); // System.out.println("num2 :" + num2); numStack.push(num1 / num2); // System.out.println("pushed / num = " + num1 / num2); } else if (com == '-') { int num2 = numStack.pop(); // System.out.println("num2 :" + num2); numStack.push(0 - num2); // TODO if (cStack.size() == numStack.size() - 1 || cStack.size() == numStack.size() - 2) { } else { cStack.push(com); // System.out.println("pushed - num = " + (0 - num2)); } } else { cStack.push(com); // System.out.println("Repushed compute : " + com); } } sbu = new StringBuilder(); } cStack.push(c); // System.out.println("pushed compute : " + c); } else { sbu.append(c); } } int num = Integer.parseInt(sbu.toString()); numStack.push(num); // System.out.println("pushed num == " + num); if (!cStack.isEmpty()) { char com = cStack.pop(); // System.out.println("got compute :" + com); if (com == '*') { int num2 = numStack.pop(); int num1 = numStack.pop(); numStack.push(num1 * num2); // System.out.println("pushed * num = " + num1 * num2); } else if (com == '/') { int num2 = numStack.pop(); int num1 = numStack.pop(); numStack.push(num1 / num2); // System.out.println("pushed / num = " + num1 / num2); } else if (com == '-') { int num2 = numStack.pop(); numStack.push(0 - num2); // System.out.println("pushed - num = " + (0 - num2)); // System.out.println(cStack.size()); // System.out.println(numStack.size()); // TODO if (cStack.size() == numStack.size() - 1 || cStack.size() == numStack.size() - 2) { } else { cStack.push(com); // System.out.println("Repushed comoute = " + com); } } else { cStack.push(com); // System.out.println("Repushed compute : " + com); } } while ((!cStack.isEmpty()) || (numStack.size() >= 2)) { if (numStack.size() == 1) { break; } int num2 = numStack.pop(); // System.out.println("num2 :" + num2); int num1 = numStack.pop(); // System.out.println("num1 :" + num1); char c = '+'; if (cStack.isEmpty()) { } else { c = cStack.pop(); // System.out.println("compute:" + c); } if (c == '+') { numStack.push(num1 + num2); // System.out.println("+" + (num1 + num2)); } else if (c == '-') { numStack.push(num1 + num2); // System.out.println("-" + (num1 + num2)); } else if (c == '*') { numStack.push(num1 * num2); // System.out.println("*" + (num1 * num2)); // System.out.println("size = " + numStack.size()); } else if (c == '/') { numStack.push(num1 / num2); // System.out.println("/" + (num1 / num2)); } } result = numStack.pop(); // System.out.println("result:" + result); return String.valueOf(result); } }
我的基本思路(仅供参考):首先计算括号里面的表达式,每次分离出来括号内的内容单独计算,这样每次计算就仅仅是加减乘除的运算了;再其次,当括号内的内容计算完成后,将原有的表达式的括号部分替换成计算出来的值,直至所有括号内容全部被替换;因为不用考虑表达式是否合法的问题(括号匹配),那么将最后的表达式进行计算则可以得出结果。
需要注意:①判定括号的逻辑:是最后一个左括号和左括号后的第一个右括号,这里需要判定的是右括号的下标是否大于左括号,在代码25行处;②加减乘除运算优先级:乘除运算优先级要大于加减运算,我在此处给出的解决办法是:当遇到下一个运算符时,需要判定上一个运算符是否为'*'、'/'运算,如果是,则需要先进行'*'、'/'运算,将两个运算数取出做运算然后将结果放入栈,再遇到下一个运算符的时候,再判定当前的运算符是否为'*'or'/',这样最后最多只剩下一个'*'or'/'运算,更好计算;③减法运算会得出负数:减法运算时,需要特殊处理,其一是因为结果可能为负数,其二是因为可能是两个负数相减,这里我的处理方法是,判定当前符号是否为'-',若是'-',那么我将'-x'一起存入栈(代码143行),在最后做减法操作时(代码178行),和前一个数相加,这样处理起来相较于直接运算更为便捷,不用再考虑复杂情况;④入栈出栈逻辑:如果没有遇到运算符,则在原来的字符串(若存在)后append该字符,当且仅当上一个运算数结束了才会遇到运算符时,则此时将存有数值的字符串转换成Integer类型并存入数值栈(numStack),若运算符栈(cStack)非空,则按照第②步运算逻辑根据在栈中的运算符(上一个运算符)运算。
上述代码可简化,分离括号逻辑可以重新在另一个函数中完成,主函数仅仅完成传输表达式和得出结论的操作即可。总之,代码很丑陋,思路很大众,大家做个参考,有更好的想法欢迎评论。