5 简单四则运算解析器
实现一个基本的计算器来计算一个简单的字符串表达式的值。注意事项如下:
-
输入是一个字符串表达式(可以假设所给定的表达式都是有效的)
-
字符串表达式可以包含的运算符号为:左括号
(
, 右括号)
, 加号+
, 减号-
-
可以包含的数字为:非负整数(< 10)
-
字符串中不包含空格
-
处理除法 case 的时候,可以直接省略小数部分结果,只保留整数部分参与后续运算
-
请不要使用内置的库函数
eval
输入格式
如:3+4*5/(3+2)
数据约束
见题目描述
输出格式
计算之后的数字
输入样例:
1+1
3+4*5/(3+2)
4+2*5-2/1
(1+(4+5+2)-3)+(6+8)
输出样例:
2
7
12
23
主要思路:
-
使用栈(Stack)来管理操作数和运算符:
- 操作数栈(Operand Stack) :用于存储数字。
- 运算符栈(Operator Stack) :用于存储运算符和括号。
-
遍历表达式:
-
数字:直接推入操作数栈。
-
左括号
(
:推入运算符栈,标志着一个新的表达式块的开始。 -
右括号
)
:弹出运算符栈中的运算符,并执行相应的运算,直到遇到左括号(
。 -
运算符
+
,-
,*
,/
:- 在运算符栈顶有更高或相同优先级的运算符时,先执行栈顶运算符的运算。
- 然后将当前运算符推入运算符栈。
-
-
处理剩余的运算符:
- 遍历完整个表达式后,弹出运算符栈中剩余的运算符,并执行相应的运算。
-
最终结果:
- 操作数栈中剩下的唯一一个数字即为表达式的计算结果。
具体步骤:
-
初始化:
- 创建两个栈:
operandStack
用于存储操作数,operatorStack
用于存储运算符和括号。 - 定义运算符的优先级:
+
和-
的优先级低于*
和/
。
- 创建两个栈:
-
遍历表达式:
-
对于每个字符
c
:-
如果是数字:
- 将其转换为整数并推入
operandStack
。
- 将其转换为整数并推入
-
如果是左括号
(
:- 推入
operatorStack
。
- 推入
-
如果是右括号
)
:- 弹出
operatorStack
中的运算符,并执行相应运算,直到遇到左括号(
。
- 弹出
-
如果是运算符
+
,-
,*
,/
:- 当
operatorStack
不为空,且栈顶运算符的优先级大于或等于当前运算符的优先级时,弹出栈顶运算符并执行运算。 - 将当前运算符推入
operatorStack
。
- 当
-
-
-
处理剩余的运算符:
- 遍历完表达式后,弹出
operatorStack
中剩余的运算符,并执行相应运算。
- 遍历完表达式后,弹出
-
获取结果:
- 操作数栈中最后剩下的数字即为表达式的计算结果。
算法实现
import java.util.*;
public class Main {
public static int solution(String expression) {
// Please write your code here
// 创建操作数栈和运算符栈
Stack<Integer> operandStack = new Stack<>();
Stack<Character> operatorStack = new Stack<>();
int n = expression.length();
for(int i = 0; i < n; i++) {
char c = expression.charAt(i);
if(Character.isDigit(c)) {
// 由于题目中数字都是单个数字(0-9),直接转换并推入操作数栈
operandStack.push(c - '0');
}
else if(c == '(') {
// 左括号,推入运算符栈
operatorStack.push(c);
}
else if(c == ')') {
// 右括号,弹出运算符并执行,直到遇到左括号
while(!operatorStack.isEmpty() && operatorStack.peek() != '(') {
char op = operatorStack.pop();
applyOperator(operandStack, op);
}
// 弹出左括号 '('
if(!operatorStack.isEmpty()) {
operatorStack.pop();
}
}
else if(isOperator(c)) {
// 当前字符是运算符
while(!operatorStack.isEmpty() && precedence(operatorStack.peek()) >= precedence(c)) {
char op = operatorStack.pop();
applyOperator(operandStack, op);
}
// 推入当前运算符
operatorStack.push(c);
}
}
// 处理剩余的运算符
while(!operatorStack.isEmpty()) {
char op = operatorStack.pop();
applyOperator(operandStack, op);
}
// 操作数栈中最后的数字就是结果
return operandStack.pop();
}
/**
* 判断字符是否是运算符
* @param c 输入字符
* @return 如果是运算符返回 true,否则返回 false
*/
private static boolean isOperator(char c) {
return c == '+' || c == '-' || c == '*' || c == '/';
}
/**
* 获取运算符的优先级
* @param op 运算符
* @return 优先级数值,数值越大优先级越高
*/
private static int precedence(char op) {
if(op == '+' || op == '-') {
return 1;
}
else if(op == '*' || op == '/') {
return 2;
}
return 0;
}
/**
* 执行运算符的运算,并将结果推回操作数栈
* @param operandStack 操作数栈
* @param operator 当前运算符
*/
private static void applyOperator(Stack<Integer> operandStack, char operator) {
// 弹出两个操作数
int b = operandStack.pop();
int a = operandStack.pop();
int result = 0;
switch(operator) {
case '+':
result = a + b;
break;
case '-':
result = a - b;
break;
case '*':
result = a * b;
break;
case '/':
// 整数除法,自动舍弃小数部分
result = a / b;
break;
}
// 将结果推回操作数栈
operandStack.push(result);
}
public static void main(String[] args) {
// You can add more test cases here
System.out.println(solution("1+1") == 2);
System.out.println(solution("3+4*5/(3+2)") == 7);
System.out.println(solution("4+2*5-2/1") == 12);
System.out.println(solution("(1+(4+5+2)-3)+(6+8)") == 23);
}
}