224.基本计算器
实现一个基本的计算器来计算一个简单的字符串表达式的值。
字符串表达式可以包含左括号 ( ,右括号 ),加号 + ,减号 -,非负整数和空格 。
import java.util.Stack;
public class _224_基本计算器1 {
public int calculate(String s) {
Stack<Integer> stack1 = new Stack<>();//stack1中最多存储3个值
Stack<Character> stack2 = new Stack<>();// stack2中最多存储2个运算符
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == '(') { // (
stack2.push(c);
} else if (c == ')') { // )
while (stack2.peek() != '(') {
char label = stack2.peek();
reversePolish(label,stack1);
stack2.pop();
}
stack2.pop();
} else if (Character.isDigit(c)) { // 数字
add(stack1,c,s,i);
} else {
if (c != ' ') {// + - * /
if (stack2.isEmpty()) {
stack2.push(c);
}
else if (stack2.peek() == '(') {
stack2.push(c);
} else if ((stack2.peek() == '+' || stack2.peek() == '-') && (c == '*' || c=='/') ) {
stack2.push(c);
} else {
char lable = stack2.peek();
reversePolish(lable,stack1);
stack2.pop();
stack2.push(c);
}
}
}
}
while (!stack2.isEmpty()) {
char label = stack2.peek();
reversePolish(label,stack1);
stack2.pop();
}
return stack1.pop();
}
// 计算逆波兰表达式 如:1 1 -
private void reversePolish(char label, Stack<Integer> stack1) {
int right = stack1.pop();
int left = stack1.pop();
switch (label) {
case '+' :
stack1.push(left + right);
break;
case '-' :
stack1.push(left - right);
break;
case '*' :
stack1.push(left * right);
break;
case '/':
stack1.push(left / right);
break;
}
}
private void add(Stack<Integer> stack1, char c, String s, int i) {
if (stack1.isEmpty()) {
stack1.push(c-'0');
} else {
if (Character.isDigit(s.charAt(i-1))){//23
stack1.push(((int)stack1.pop())*10 + (c - '0'));
} else {
stack1.push(c-'0');
}
}
}
}
一共用到三个函数
- calculate 主函数
- reversePolish 逆波兰函数(输入3个元素)例:111 2 + -> 113
- add 数字字符串处理,例:"123" -> 123
calculate 主函数思路 示例:(1+2+(4+5+2)-3)+(6+8)
将中缀表达式转化为后缀表达式
- 准备两个栈,stack1、stack2。stack1存储操作数,stack2存储操作符
- 遍历字符串s每一个字符c
- c可能的值是
' '
,'('
,')'
,'+'
,'-'
,'*'
,'/'
,'数字字符'
- 操作符优先级:加减 < 乘除 ,先入栈的加减 > 后入栈的加减, 先入栈的乘除>后入栈的乘除
char c | 操作 | |
---|---|---|
'(' | 压入stack2 | |
')' | 依次将stack2中元素出栈到stack2,直至遇到'(' ,将'('出栈 | |
'+' | 将栈中比'+'优先级高的操作符出栈到stack1,没有的话就不出栈。将'+'入栈 | 如果栈顶是'+'或'-'则'+'或'-'优先级比'+'高 |
'-' | 类似于'+' | |
'*' | 类似于'+' | |
'/' | 类似于'+' | |
'数字' | 如果stack1为空,直接将c-'0'压入stack1。如果c的前一个字符是数字,将栈stack1栈顶元素弹出乘以10加c-'0'的值 | 如111 |
为了区分不同位置加号,使用'+_数字'表示加号 | ||
(111+2+3)/2+1 -> 111 2 + 3 + 2 / 1 + |
c | stack1 | stack2 | stack1优化 |
---|---|---|---|
'(' | [] | [] | [] |
'1' | [] | ['('] | [] |
'1' | [1] | ['('] | [1] |
'1' | [11] | ['('] | [11] |
'+_1' | [111] | ['('] | [111] |
'2' | [111] | ['(', '+_1'] | [111] |
'+_2' | [111, 2] | ['(', '+_2'] | [111, 2] |
'3' | [111, 2,'+_1'] | ['(', '+_2'] | [113] |
')' | [111, 2,'+_1',3] | ['(', '+_2'] | [113,3] |
'/' | [111, 2,'+_1',3,'+_2'] | [] | [116] |
'2' | [111, 2,'+_1',3,'+_2'] | ['/'] | [116] |
'+_3' | [111, 2,'+_1',3,'+_2',2] | ['/'] | [116,2] |
'1' | [111, 2,'+_1',3,'+_2',2,'/'] | ['+_3'] | [58] |
[111, 2,'+_1',3,'+_2',2,'/',1] | ['+_3'] | [58,1] |
- 栈stack1可以优化,当stack1入栈操作符时,改为直接执行逆波兰表达式(将stack1栈顶两个操作数弹出,记为left、right执行对应的加减乘除),stack1中只存操作数
- 最后stack2中的栈顶弹出,stack1中两元素弹出,执行最后的逆波兰表达式,得到最终计算结果