问题描述
小F面临一个编程挑战:实现一个基本的计算器来计算简单的字符串表达式的值。该字符串表达式有效,并可能包含数字(0-9)、运算符+、-及括号()。注意,字符串中不包含空格。除法运算应只保留整数结果。请实现一个解析器计算这些表达式的值,且不使用任何内置的eval函数。
问题理解
我们需要实现一个基本的计算器来计算简单的字符串表达式的值。表达式可能包含数字(0-9)、运算符+、-、、/及括号()。除法运算应只保留整数结果。 数据结构选择 栈(Stack):我们使用两个栈,一个用于存储数字(numStack),另一个用于存储运算符(opStack)。栈的特性(后进先出)非常适合处理表达式中的运算符优先级和括号。 算法步骤 遍历表达式:从左到右遍历表达式中的每个字符。 处理数字:如果当前字符是数字,则继续读取后续的数字字符,直到遇到非数字字符,然后将完整的数字压入numStack。 处理左括号:如果当前字符是左括号(,则将其压入opStack。 处理右括号:如果当前字符是右括号),则从opStack中弹出运算符并从numStack中弹出两个数字进行计算,直到遇到左括号(。 处理运算符:如果当前字符是运算符(+、-、、/),则根据运算符优先级决定是否立即进行计算,或者将当前运算符压入opStack。 处理剩余运算符:遍历结束后,处理opStack中剩余的运算符。
代码详解
import java.util.Stack;
public class Main { public static int solution(String expression) { Stack numStack = new Stack<>(); Stack opStack = new Stack<>();
int i = 0;
while (i < expression.length()) {
char ch = expression.charAt(i);
if (Character.isDigit(ch)) {
int num = 0;
while (i < expression.length() && Character.isDigit(expression.charAt(i))) {
num = num * 10 + (expression.charAt(i) - '0');
i++;
}
numStack.push(num);
} else if (ch == '(') {
opStack.push(ch);
i++;
} else if (ch == ')') {
while (!opStack.isEmpty() && opStack.peek() != '(') {
numStack.push(applyOp(opStack.pop(), numStack.pop(), numStack.pop()));
}
opStack.pop(); // 弹出左括号
i++;
} else if (ch == '+' || ch == '-' || ch == '*' || ch == '/') {
while (!opStack.isEmpty() && hasPrecedence(ch, opStack.peek())) {
numStack.push(applyOp(opStack.pop(), numStack.pop(), numStack.pop()));
}
opStack.push(ch);
i++;
}
}
while (!opStack.isEmpty()) {
numStack.push(applyOp(opStack.pop(), numStack.pop(), numStack.pop()));
}
return numStack.pop();
}
public static boolean hasPrecedence(char op1, char op2) {
if (op2 == '(' || op2 == ')') {
return false;
}
if ((op1 == '*' || op1 == '/') && (op2 == '+' || op2 == '-')) {
return false;
}
return true;
}
public static int applyOp(char op, int b, int a) {
switch (op) {
case '+':
return a + b;
case '-':
return a - b;
case '*':
return a * b;
case '/':
if (b == 0) {
throw new UnsupportedOperationException("Cannot divide by zero");
}
return a / b; // 确保结果为整数
}
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);
}
}
知识总结
栈的应用:栈在处理表达式计算、括号匹配等问题中非常有用。通过栈,我们可以轻松地回溯和处理嵌套的表达式。
运算符优先级:理解运算符优先级是编写表达式解析器的关键。通过栈和优先级判断,我们可以确保计算顺序正确。
整数除法:在实际编程中,整数除法的结果可能与浮点数除法不同,需要注意结果的类型和精度。
学习建议
理解数据结构:栈、队列、链表等数据结构是编程的基础,理解它们的特性和应用场景非常重要。
多练习:通过刷题,尤其是涉及栈和表达式解析的题目,可以加深对数据结构和算法的理解。
总结经验:每次刷题后,总结解题思路和遇到的问题,形成自己的知识库。
学习计划
制定刷题计划:每天刷一定数量的题目,逐步提高难度。 利用错题:对于做错的题目,分析错误原因,总结经验,避免再次犯错。 结合AI工具:利用MarsCode AI的刷题功能,获取解题思路和代码提示,提高学习效率。