1. 问题描述:
实现一个基本的计算器来计算一个简单的字符串表达式的值。字符串表达式可以包含左括号 ( ,右括号 ),加号 + ,减号 -,非负整数和空格 。
示例 1:
输入: "1 + 1"
输出: 2
示例 2:
输入: " 2-1 + 2 "
输出: 3
示例 3:
输入: "(1+(4+5+2)-3)+(6+8)"
输出: 23
说明:
你可以假设所给定的表达式都是有效的。
请不要使用内置的库函数 eval。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/basic-calculator
2. 思路分析:
① 这道题目实际上是栈的应用,我们需要先求出题目中给出的中缀表达式对应的后缀表达式,然后再计算后缀表达式的值即可,之前写过同样的博客,也是对存在括号的中缀表达式进行求值,之前写的那篇博客挺详细的,所以这里就不详细阐述了
② 在求解的过程中使用到栈和队列,栈是可以用来存放操作符,队列可以存放后缀表达式,当遍历到的为数字的时候直接进队列,当遍历到的为左括号的时候直接把左括号进栈,为右括号的时候进入循环找到与之匹配的左括号,并且栈中弹出的操作符进队列中,最后弹出栈中与之匹配的左括号,当为操作符的时候需要注意当前的操作符与栈顶操作符的优先级问题,假如栈为空,操作符直接入队,假如不为空的情况下需要注意优先级的问题:
1)当栈顶元素为左括号的时候直接将遍历的元素入栈
2)当栈顶元素为-、+并且遍历的元素为/、*的时候这个时候优先级是大于栈顶元素的,可以将遍历的元素直接入栈
3)当栈顶元素与当前遍历的元素为同一级别的操作符的时候,此时遍历元素的优先级是小于了栈顶元素的优先级的,这个时候需要弹出栈中操作符到队列中知道优先级大于了栈顶元素的还有其他的情况也是遍历元素的优先级小于了栈顶元素的,这些求解后缀表达式基本的步骤,没有太多需要理解的地方
③ 遍历字符串结束的时候那么队列中存储的就是后缀表达式了,我们只需要计算后缀表达式的值即可,当队列非空的情况下弹出元素,这个时候需要一个栈来辅助得到结果,当发现弹出的元素为数字的时候直接进栈,当为操作符的时候弹出两个操作数,并且由于存储到栈中,所以要注意弹出操作数的计算顺序,并将计算的结果压入堆栈,等到队列为空的情况下栈顶元素就是整个后缀表达式的值了
3. 代码如下:
class Solution {
public int calculate(String s) {
Stack<Character> stack = new Stack<>();
Queue<String> queue = new LinkedList<>();
for (int i = 0; i < s.length(); ++i){
char c = s.charAt(i);
/*左括号直接入栈*/
if (c == ' ') continue;
else if (c == '('){
stack.push(c);
}else if (c == ')'){
/*匹配左括号将这一对括号的符号压入到队列中*/
while (!stack.isEmpty() && stack.peek() != '('){
queue.add(stack.pop() + "");
}
/*需要弹出左括号*/
stack.pop();
}else if (c >= '0' && c <= '9'){
int sum = 0;
/*数字的时候需要将将大于10的数字计算出来*/
while (i < s.length() && c >= '0' && c <= '9'){
/*i放在前面的时候比较好处理越界的问题*/
sum = sum * 10 + (c - '0');
if (++i < s.length()) c = s.charAt(i);
}
queue.add(sum + "");
--i;
}else{
/*操作符: 最后一个来判断操作符的话可能比较好*/
if (stack.isEmpty()) stack.push(c);
else{
/*判断操作符的优先级: 弹出优先级较小的到后缀表达式的队列中去*/
while (!stack.isEmpty() && !prior(stack.peek(), c)){
queue.add(stack.pop() + "");
}
stack.push(c);
}
}
}
while (!stack.isEmpty()) queue.add(stack.pop() + "");
return cal(queue);
}
/*后缀表达式计算表达式的值*/
private int cal(Queue<String> queue) {
/*计算后缀表达式需要使用一个栈来做辅助*/
Stack<Integer> res = new Stack<>();
while (!queue.isEmpty()){
/*先判断操作符*/
String cur = queue.poll();
if (cur.equals("+") || cur.equals("-") || cur.equals("*") || cur.equals("/")){
/*一定要注意交换顺序因为存储的是在栈中的*/
String num2 = res.pop() + "";
String num1 = res.pop() + "";
int sum = twoCal(num1, num2, cur);
res.add(sum);
}else {
res.add(Integer.parseInt(cur));
}
}
return res.peek();
}
private int twoCal(String num1, String num2, String cur) {
int n1 = Integer.parseInt(num1);
int n2 = Integer.parseInt(num2);
if (cur.equals("+")) return n1 + n2;
else if (cur.equals("-")) return n1 - n2;
else if (cur.equals("/")) return n1 / n2;
return n1 * n2;
}
private boolean prior(char peek, char c) {
if (peek == '(') return true;
else if (c == '+' || c == '-') return false;
if ((c == '*' || c == '/') && peek == '*' || peek == '/') return false;
return true;
}
}