题目描述
给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。
样例描述
示例 1:
输入:s = "1 + 1"
输出:2
示例 2:
输入:s = " 2-1 + 2 "
输出:3
示例 3:
输入:s = "(1+(4+5+2)-3)+(6+8)"
输出:23
思路
表达式求值 (通用模板题)
- 维护一个栈,如果遇到数就直接压入栈。遇到左括号也压入栈,遇到右括号将左括号之前的全算完。
- 遇到运算符的话,首先定义运算符的优先级如下,保证能够区分即可。
如果当前运算符优先级小于等于栈顶优先级,则计算栈顶,算完会有新的栈顶,然后压入栈中(继续比较然后计算,while循环过程)
如果当前运算符大于栈顶优先级,则压入栈中。
表达式求值的通用模板的整体流程如下:
- 由于数和字符的类型不一样,需要用两个栈表示。一个存数,一个存运算符。
- 细节由于第一个数可能是负数,为了减少边界判断。先往 nums 添加一个 0。(也可以开始直接给s加个括号,然后变成下面的细节处理,在循环逻辑中处理掉)
- 细节防止 () 内出现的首个字符为运算符,将所有的空格去掉,并将 (- 替换为 (0-,(+ 替换为 (0+,在循环中处理这个细节。
- java函数名过长,为方便可以封装Character.isDigit这个方法,可以将字符串转化为字符数组方便索引里面的值。
代码
class Solution {
Deque<Integer> nums = new LinkedList<>();
Deque<Character> ops = new LinkedList<>();
public int calculate(String s) {
// //防止第一个数是负数,先加入一个0
// nums.addLast(0);
s = '(' + s + ')';
//去掉字符串中所有空格
s = s.replaceAll(" ", "");
//转化为字符数组,方便索引字符
char ch[] = s.toCharArray();
int n = s.length();
for (int i = 0; i < n; i ++ ) {
char c = ch[i];
//数的话,用双指针截取出数,并用字符串转数来求得这个数
if (isNum(c)) {
int j = i, num = 0;
while (j < n && isNum(ch[j])) {
//转为int防止越界
num = num * 10 + (int)(ch[j ++] - '0');
}
i = j - 1; //类似双指针中,移动下标,j - 1因为循环还会移动1
nums.addLast(num);
} else if (c == '(') {
ops.addLast(c);
} //右括号的话,前面的直到最近的左括号都要计算完
else if (c == ')') {
// 计算到最近一个左括号为止
// while (!ops.isEmpty()) {
// char op = ops.peekLast();
// if (op != '(') {
// eval();
// } else {
// ops.pollLast();
// break;
// }
// }
while (ops.peekLast() != '(') eval();
ops.pollLast();
// while (ops.peekLast() != '(') eval();
// //弹出左括号
// ops.pollLast();
} //对运算符
else {
// 特殊处理符号,如果前一个是(、+、-,当前又是运算符,就补一个0在中间
if (i > 0 && (ch[i - 1] == '(' || ch[i - 1] == '+' || ch[i - 1] == '-'))
nums.addLast(0);
//有新的操作符要入栈,由于这里没有优先级大小区分,就直接把栈内的都算了
while (!ops.isEmpty() && ops.peekLast() != '(') {
eval();
}
//算完后将新的操作符入栈
ops.addLast(c);
}
}
//防止还有没算完的,收尾
while (!ops.isEmpty()) {
eval();
}
return nums.peekLast();
}
//计算函数
public void eval() {
// //边界判断,数栈为空或者不足两个数,或者操作栈为空 直接返回
// if (nums.isEmpty() || nums.size() < 2) return;
// if (ops.isEmpty()) return;
//先弹出的是b,后弹出的是a,因为插入顺序与弹出的相反
int b = nums.pollLast();
int a = nums.pollLast();
if (ops.pollLast() == '+') nums.addLast(a + b);
else nums.addLast(a - b);
}
public boolean isNum(char c) {
return Character.isDigit(c);
}
}