问题描述
小F面临一个编程挑战:实现一个基本的计算器来计算简单的字符串表达式的值。该字符串表达式有效,并可能包含数字(0-9)、运算符+、-及括号()。注意,字符串中不包含空格。除法运算应只保留整数结果。请实现一个解析器计算这些表达式的值,且不使用任何内置的eval函数。
测试样例
样例1:
输入:
expression = "1+1"
输出:2
样例2:
输入:
expression = "3+4*5/(3+2)"
输出:7
样例3:
输入:
expression = "4+2*5-2/1"
输出:12
样例4:
输入:
expression = "(1+(4+5+2)-3)+(6+8)"
输出:23
样例5:
输入:
expression = "2*(5+5*2)/3+(6+8*3)"
输出:40
问题理解
你需要实现一个基本的计算器来计算简单的字符串表达式的值。该字符串表达式有效,并可能包含数字(0-9)、运算符+、-、*、/及括号()。注意,字符串中不包含空格。除法运算应只保留整数结果。
数据结构选择
- 栈:我们可以使用两个栈,一个用于存储操作数(数字),另一个用于存储运算符。栈非常适合处理括号和运算符优先级的问题。
算法步骤
-
遍历表达式:从左到右遍历表达式中的每个字符。
-
解析数字:如果当前字符是数字,解析完整的数字并压入操作数栈。
-
处理括号:
- 遇到左括号
(时,直接压入运算符栈。 - 遇到右括号
)时,计算直到遇到左括号。
- 遇到左括号
-
处理运算符:
- 遇到运算符时,检查运算符栈顶的运算符,如果栈顶运算符优先级较高,则先进行栈顶运算符的计算。
- 将当前运算符压入运算符栈。
-
计算结果:遍历结束后,处理运算符栈中剩余的运算符,直到运算符栈为空。
具体步骤
-
初始化两个栈:一个用于操作数,一个用于运算符。
-
遍历表达式:
- 如果是数字,解析完整的数字并压入操作数栈。
- 如果是左括号
(,压入运算符栈。 - 如果是右括号
),计算直到遇到左括号。 - 如果是运算符,处理运算符优先级。
-
处理剩余运算符:遍历结束后,处理运算符栈中剩余的运算符。
-
返回结果:最终结果在操作数栈的栈顶。
代码如下:
import java.util.Stack;
public class Main { public static int solution(String expression) { // 使用两个栈,一个用于操作数,一个用于运算符 Stack numStack = new Stack<>(); Stack opStack = new Stack<>();
// 遍历表达式中的每个字符
for (int i = 0; i < expression.length(); i++) {
char ch = expression.charAt(i);
// 如果是数字,解析完整的数字并压入numStack
if (Character.isDigit(ch)) {
int num = 0;
while (i < expression.length() && Character.isDigit(expression.charAt(i))) {
num = num * 10 + (expression.charAt(i) - '0');
i++;
}
i--; // 回退一步,因为for循环会再前进一步
numStack.push(num);
}
// 如果是左括号,压入opStack
else if (ch == '(') {
opStack.push(ch);
}
// 如果是右括号,计算直到遇到左括号
else if (ch == ')') {
while (!opStack.isEmpty() && opStack.peek() != '(') {
// 计算并压入结果
numStack.push(applyOp(opStack.pop(), numStack.pop(), numStack.pop()));
}
opStack.pop(); // 弹出左括号
}
// 如果是运算符,处理运算符优先级
else if (ch == '+' || ch == '-' || ch == '*' || ch == '/') {
while (!opStack.isEmpty() && precedence(opStack.peek()) >= precedence(ch)) {
// 计算并压入结果
numStack.push(applyOp(opStack.pop(), numStack.pop(), numStack.pop()));
}
opStack.push(ch);
}
}
// 处理剩余的运算符
while (!opStack.isEmpty()) {
numStack.push(applyOp(opStack.pop(), numStack.pop(), numStack.pop()));
}
// 最终结果在numStack的栈顶
return numStack.pop();
}
// 计算两个数的运算结果
private static int applyOp(char op, int b, int a) {
switch (op) {
case '+': return a + b;
case '-': return a - b;
case '*': return a * b;
case '/': return a / b; // 注意:这里假设b不为0
}
return 0;
}
// 返回运算符的优先级
private static int precedence(char op) {
if (op == '+' || op == '-') return 1;
if (op == '*' || op == '/') return 2;
return 0;
}
public static void main(String[] args) {
// 你可以添加更多测试用例
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);
}
}