150. 逆波兰表达式求值
✨核心逻辑
本题采用 栈(Stack) 的处理策略:
- 遇数入栈:遍历整个字符串数组,如果遇到的是数字,将其转换为
int类型后直接压入栈中。 - 遇符出栈:如果遇到的是运算符,则从栈顶弹出两个数字(即当前运算符所需要的两个操作数)。
- 注意顺序:由于栈是后进先出的结构,先弹出的数字
pop1其实是表达式中的“右侧操作数”,后弹出的数字pop2是“左侧操作数”。因此,对于减法和除法,要特别注意顺序:执行pop2 - pop1和pop2 / pop1。 - 结果入栈:将计算得到的结果重新压入栈中,供后续的运算使用。
- 返回结果:当所有元素遍历处理完毕后,栈中唯一的数字就是这个算术表达式的最终结果。
🔥代码实现(含详细变量注释)
class Solution {
public int evalRPN(String[] tokens) {
// 边界情况:如果表达式只有一个数字,直接将其转换并返回
if (tokens.length == 1) {
return Integer.valueOf(tokens[0]);
}
// deque:使用双端队列来模拟栈结构,比旧版 Stack 类性能更好
Deque<Integer> deque = new ArrayDeque<>();
// result:用于记录当前运算符计算出来的临时结果
int result = 0;
// st:遍历指针,依次读取字符串数组中的每一个字符元素(可能是数字,也可能是运算符)
for (String st : tokens) {
// 如果当前字符串是运算符
if (st.equals("+") || st.equals("-") || st.equals("*") || st.equals("/")) {
// pop1:栈顶元素,是当前运算符的右侧操作数(先弹出的数)
int pop1 = Integer.valueOf(deque.pop());
// pop2:次栈顶元素,是当前运算符的左侧操作数(后弹出的数)
int pop2 = Integer.valueOf(deque.pop());
// 根据不同的运算符执行不同的数学运算
if (st.equals("+")) {
result = pop1 + pop2;
}
if (st.equals("-")) {
// 注意:减法必须用“左侧操作数 - 右侧操作数”
result = pop2 - pop1;
}
if (st.equals("*")) {
result = pop1 * pop2;
}
if (st.equals("/")) {
// 注意:除法必须用“左侧操作数 / 右侧操作数”(题目保证不会除零)
result = pop2 / pop1;
}
// 将本次计算的结果重新压入栈中,作为下一步运算的数据
deque.push(result);
} else {
// 如果当前字符串不是运算符,说明是操作数(数字)
// 将其转换为 int 后直接压入栈中
deque.push(Integer.valueOf(st));
}
}
// 遍历结束后,栈中剩下的最后一个数字即为表达式最终计算结果
return result;
}
}
- ⏱️复杂度分析
时间复杂度:O(N),其中 N 是逆波兰表达式数组 tokens 的长度。我们只需要对数组进行一次遍历,遍历过程只涉及常数次的栈弹出和压入操作。
空间复杂度:O(N),最坏情况下,表达式中全都是数字没有运算符,此时栈的大小会达到 N,用于存储所有中间结果和操作数。