给你一个字符串表达式 s
,请你实现一个基本计算器来计算并返回它的值。
示例 1:
输入:s = "1 + 1" 输出:2
示例 2:
输入:s = " 2-1 + 2 " 输出:3
示例 3:
输入:s = "(1+(4+5+2)-3)+(6+8)" 输出:23
思路:
- 使用栈模拟,一个符号栈,一个操作数栈。
- 当遇到 "(" 时,直接放进符号栈。
- 当遇到 ")" 时,不断弹出符号栈中的符号并进行计算,直到遇到 "(" ,此时将 "(" 弹出终止。
- 当遇到 加减乘除 符号时,当符号栈栈顶符号优先级大于当前的符号位的优先级时进行运算。
计算:操作是指弹出操作数栈的两个数字根据符号栈的栈顶符号位进行运算。
符号优先级:"(" = ")" < "+" = "-" < "*" = "/"
操作数栈补0的特殊处理:1. 符号位出现在首字母 2. "(-" 或者 "(+" 两种情形
JAVA 代码实现
class Solution {
// 符号栈
private Deque<Character> opQ = new ArrayDeque<>();
// 数字栈
private Deque<Integer> numQ = new ArrayDeque<>();
// 符号优先级
private Map<Character, Integer> map = new HashMap<Character, Integer>() {{
put('(', -1);
put(')', -1);
put('+', 0);
put('-', 0);
put('*', 1);
put('/', 1);
}};
// 弹出两个数字和一个符号进行计算
private void compute() {
int a = numQ.pop();
int b = numQ.pop();
char op = opQ.pop();
int ans = 0;
switch (op) {
case '+': ans = a + b; break;
case '-': ans = b - a; break;
case '*': ans = a * b; break;
case '/': ans = b / a; break;
default: break;
}
// 运算结果进栈
numQ.push(ans);
}
public int calculate(String s) {
// 过滤掉空格
s = s.replaceAll(" ", "");
char[] cs = s.toCharArray();
int n = cs.length;
// 特殊情况,第一位字符为符号位,操作数栈补0
if (cs[0] == '+' || cs[0] == '-') {
numQ.add(0);
}
for (int i = 0; i < n; i ++ ) {
// 数字
if (cs[i] >= '0' && cs[i] <= '9') {
int t = 0;
while (i < n && cs[i] >= '0' && cs[i] <= '9') {
t = t * 10 + (cs[i] - '0');
i ++;
}
// 结果进栈
numQ.push(t);
}
if (i >= n) break;
if (cs[i] == '(') {
opQ.push(cs[i]);
} else if (cs[i] == ')') {
// 遍历到'('才停下来
while (opQ.peek() != '(') {
compute();
}
// 弹掉'('
opQ.pop();
} else {
// 出现(-或者(+,操作数栈补0
if (i > 0 && cs[i - 1] == '(') {
numQ.push(0);
}
// 出现-1或者+1,操作数栈补0
// if (i > 0 && i < n - 1 && !(cs[i - 1] >= '0' && cs[i - 1] <= '9')) {
// numQ.push(0);
// }
// 栈顶的符号优先级比当前符号的优先级大,进行运算
if (!opQ.isEmpty() && map.get(opQ.peek()) >= map.get(cs[i])) {
compute();
}
// 进栈
opQ.push(cs[i]);
}
}
// 兜底,防止还能进行运算
while (!opQ.isEmpty()) {
compute();
}
// 最终操作数栈中只剩下最后的结果
return numQ.peek();
}
}