leetcode:224. 基本计算器 I、227. 基本计算器 II
程序员文章站
2022-07-14 14:10:55
...
224.标题基本计算器 I
通用解法就不说了,这里介绍下用正则表达式来解这道题,基本思路是先用正则表达式计算出括号中的子表达式,最后计算整个表达式。代码如下:
import java.util.Arrays;
import java.util.regex.*;
class Solution {
public int calculate(String s) {
s = s.replace(" ", "");
return calculateExp(s);
}
Pattern splitPattern = Pattern.compile("\\([\\d\\+\\-]+\\)");
// 计算表达式
public int calculateExp(String s) {
if (s.matches("[\\-]?[\\d]+")) {// 判断是否计算结束
return Integer.parseInt(s);
}
StringBuilder sb = new StringBuilder(s);
Matcher matcher = splitPattern.matcher(s);
if (matcher.find()) {
int start = matcher.start();
int end = matcher.end();
// System.err.println(start + " " + end);
int value = calValue(s.substring(start + 1, end - 1));
String valueStr = value + "";
if (value < 0 && start > 0) {// 有点烦,计算结果是负数要处理下
char op = s.charAt(start - 1);
if (op == '-') {
valueStr = "+" + (-value);
}
start -= 1;
}
sb.replace(start, end, valueStr);
} else {
sb.replace(0, s.length(), "" + calValue(s));// 无圆括号的表达式
}
// System.out.println(sb);
return calculateExp(sb.toString());
}
// 简单加减表达式计算
Pattern opPattern = Pattern.compile("[\\-\\+]");
public int calValue(String exp) {
// System.err.println(exp);
Matcher matcher = opPattern.matcher(exp);
String[] nums = opPattern.split(exp);
if (null == nums || nums.length < 1) {
return 0;
}
int res = Integer.parseInt(nums[0]);
for (int i = 1; i < nums.length; i++) {
if (!matcher.find()) {
return res;
}
int index = matcher.start();
String operator = exp.substring(index, index + 1);
switch (operator) {
case "+":
res += Integer.parseInt(nums[i]);
break;
case "-":
res -= Integer.parseInt(nums[i]);
break;
}
}
// System.err.println(exp + "==" + res);
return res;
}
}
227.基本计算器 II
使用通用解法,将中缀表达式转为后缀表达式,然后借助操作数栈求值(由于题设中没有圆括号,所以这里并未进行处理,但只需要新增一个方法单独处理圆括号并得到无圆括号的子表达式(注意递归),依旧调用getCalcQueue即可,其余代码无需变动)代码如下:
import java.util.*;
class Solution {
public int calculate(String s) {
return calculateExpr(s);
}
public int calculateExpr(String expr) {
Queue<Object> queue = getCalcQueue(expr);
// System.out.println(queue);
return calcQueue(queue);
}
// 借助栈计算队列的值
public int calcQueue(Queue<Object> queue) {
LinkedList<Integer> stack = new LinkedList<Integer>();// 操作数栈
while (!queue.isEmpty()) {
Object obj = queue.poll();
if (obj instanceof Character) {
int num2 = stack.pollLast();//弹出栈顶元素
int num1 = stack.pollLast();
switch ((Character) obj) {
case '+':
stack.add(num1 + num2);//注意顺序
break;
case '-':
stack.add(num1 - num2);//注意顺序
break;
case '*':
stack.add(num1 * num2);//注意顺序
break;
case '/':
stack.add(num1 / num2);//注意顺序
break;
}
} else {
stack.add(Integer.parseInt((String) obj));//数字则直接压入栈
}
}
return stack.pollLast();//栈顶元素就是结果,当前栈也只会有一个元素了
}
// 解析中缀表达式转后缀表达式后获得计算队列(不考虑圆括号)
public Queue<Object> getCalcQueue(String expr) {
LinkedList<Character> opStack = new LinkedList<Character>();// 操作符栈
Queue<Object> queue = new LinkedList<Object>();// 计算队列
String num = "";
for (int i = 0; i < expr.length(); i++) {
char ch = expr.charAt(i);
if (ch == ' ') {
continue;
}
if (Character.isDigit(ch)) {
num += ch;
} else {
if (!"".equals(num)) {// 读取到数字,直接存入queue中
queue.add(num);
num = "";
}
if (opStack.isEmpty() || (compareOp(opStack.peekLast(), ch) < 0)) {
// a.当运算符栈为空或者栈顶操作符的优先级小于当前运算符优先级时(如+和-的优先级低于 * 和 /),直接入栈
opStack.add(ch);
} else {
// b.当运算符不为空时且栈顶操作符的优先级大于或等于当前运算符优先级时,循环执行出栈操作并加入queue中,直到遇到优先级小于当前运算符的元素为止。循环执行完后再将当前运算符压栈。
while (!opStack.isEmpty() && compareOp(opStack.peekLast(), ch) >= 0) {
queue.add(opStack.pollLast());
}
opStack.add(ch);
}
}
}
queue.add(num);// 处理最后的数字
// c.表达式的值读取完后,将操作符栈中的所有元素弹出并加入到queue中
while (!opStack.isEmpty()) {
queue.add(opStack.pollLast());
}
return queue;
}
// 比较运算符的优先级,c1>c2返回1,c1=C2返回0,c1<c2返回-1
public int compareOp(Character c1, Character c2) {
if (c1.charValue() == '+' || c1.charValue() == '-') {
if (c2.charValue() == '+' || c2.charValue() == '-') {
return 0;
} else {
return -1;
}
} else {
if (c2.charValue() == '*' || c2.charValue() == '/') {
return 0;
} else {
return 1;
}
}
}
}
下一篇: 小组练习第一周-----R