题目地址:
https://www.lintcode.com/problem/expression-evaluation/description
对一个中缀表达式求值。表达式里只含加减乘除和左右小括号。
经典算法是用栈来做,一个栈专门存数字,另一个存运算符。思路可以参考用栈将中缀表达式转为后缀表达式的算法:https://blog.csdn.net/qq_46105170/article/details/106207612。后缀表达式求值是很简单的,所以本题只需要在转后缀表达式的时候顺便求值即可。代码如下:
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashMap;
import java.util.Map;
public class Solution {
/**
* @param expression: a list of strings
* @return: an integer
*/
public int evaluateExpression(String[] expression) {
// write your code here
if (expression == null || expression.length == 0) {
return 0;
}
// 开两个栈,ops存操作符,nums存操作数
Deque<String> ops = new ArrayDeque<>();
Deque<Integer> nums = new ArrayDeque<>();
// 存每个操作符的优先级
Map<String, Integer> prec = new HashMap<>();
prec.put("(", 1);
prec.put("+", 2);
prec.put("-", 2);
prec.put("*", 3);
prec.put("/", 3);
for (String s : expression) {
if (!prec.containsKey(s) && !")".equals(s)) {
// 如果遇到操作数,则进操作数栈
nums.push(Integer.parseInt(s));
} else if ("(".equals(s)) {
// 若遇到左括号,则直接进操作符栈
ops.push(s);
} else if (")".equals(s)) {
// 若遇到右括号,则将左括号到栈顶全pop出来,
// 并且和操作数栈里的数进行运算,得数再push回操作数栈;
// 在中缀转后缀的时候,是直接把操作符append到后面。
// 所以这里求值的话就直接算出值push回去就好了
while (!"(".equals(ops.peek())) {
int n2 = nums.pop(), n1 = nums.pop();
nums.push(calc(n1, n2, ops.pop()));
}
ops.pop();
} else {
// 这里的做法也是和中缀转后缀类似
while (!ops.isEmpty() && prec.get(ops.peek()) >= prec.get(s)) {
int n2 = nums.pop(), n1 = nums.pop();
nums.push(calc(n1, n2, ops.pop()));
}
ops.push(s);
}
}
// 最后还需要处理一下没算完的数
while (nums.size() > 1) {
int n2 = nums.pop(), n1 = nums.pop();
nums.push(calc(n1, n2, ops.pop()));
}
// 如果栈里不剩数了,返回0;否则返回那个数。这里主要应付全是括号的情况
return nums.isEmpty() ? 0 : nums.peek();
}
private int calc(int n1, int n2, String op) {
switch (op) {
case "+": return n1 + n2;
case "-": return n1 - n2;
case "*": return n1 * n2;
case "/": return n1 / n2;
default: return 0;
}
}
}
时空复杂度 O ( n ) O(n) O(n)。