3. <tag-栈和计算器总结>-lt.150. 逆波兰表达式求值 + lt.227. 基本计算器 || + lt.224. 基本计算器 dbc
重要: 栈与前中后缀表达式, 及波兰(给定前缀求值), 逆波兰(给定后缀求值)
- 更详细的文章请看旧文: 点我
1. 波兰运算和逆波兰运算
注意: 其实无论是根据前缀表达式计算值, 还是根据后缀表达式计算值, 出栈和入栈规则都是完全一致的!
大体上的计算规则都是遇到数字就入栈, 遇到运算符就把数字连续出栈两次进行运算, 计算的结果继续入栈;
而前缀和后缀的差别在于对给定前后缀表达式遍历次序上的区别!
1.1 逆波兰表达式计算(给定后缀表达式求值)
1.2 波兰表达式(给定前缀表达式求值)
1. 给定了中缀, 如何用栈求出后缀呢?
中缀 -> 后缀
栈用来存储运算符和左括号;
2. 给定了中缀, 如何借助栈求出前缀呢?
lt.150. 逆波兰表达式求值
[案例需求]
[思路分析一, 借助系统栈]
- 逆波兰表达式(后缀表达式)严格遵循「从左到右」的运算。
- 计算逆波兰表达式的值时,使用一个栈存储操作数,从左到右遍历逆波兰表达式,进行如下操作:
-
- 正序遍历
- 栈存储数字, 遇到运算符出栈两次进行计算, 计算结果入栈如果遇到操作数,则将操作数入栈;
- 其中先出栈的是右操作数,后出栈的是左操作数,使用运算符对两个操作数进行运算,将运算得到的新操作数入栈。
- 遍历完成, 栈中元素为最终结果
[代码实现]
class Solution {
public int evalRPN(String[] tokens) {
//逆波兰表达式
/**
数字栈, 后缀表达式正序遍历. 前缀表达式倒序遍历变为逆波兰
*/
Stack<Integer> st = new Stack<>();
/**
string => int Integer.parseInt()
int => string String.valueOf(y)
*/
//逆波兰 == 后缀表达式
// 后缀表达式计算求值
//1. 正序遍历
//2. 栈存储数字, 遇到运算符出栈两次进行计算, 计算结果入栈
//3. 遍历完成, 栈中元素为最终结果
int len = tokens.length;
for(int i = 0; i < len; i++){
String str = tokens[i];
if(isNumber(str)){
st.push(Integer.parseInt(str));
}else{
int b = st.pop();
int a = st.pop();
st.push(operation(str, a ,b));
}
}
return st.peek();
}
public static boolean isNumber(String str){
return !(str.equals("+") || str.equals("-") || str.equals("*") || str.equals("/"));
}
public int operation(String str, int a, int b){
if(str.equals("+")) return a + b;
if(str.equals("-")) return a - b;
if(str.equals("*")) return a * b;
if(str.equals("/")) return a / b;
return -1;
}
}
[思路分析二, 数组模拟栈 dbc]
[代码实现]
class Solution {
public int evalRPN(String[] tokens) {
int n = tokens.length;
int[] stack = new int[(n + 1) / 2];
int index = -1;
for (int i = 0; i < n; i++) {
String token = tokens[i];
switch (token) {
case "+":
index--;
stack[index] += stack[index + 1];
break;
case "-":
index--;
stack[index] -= stack[index + 1];
break;
case "*":
index--;
stack[index] *= stack[index + 1];
break;
case "/":
index--;
stack[index] /= stack[index + 1];
break;
default:
index++;
stack[index] = Integer.parseInt(token);
}
}
return stack[index];
}
}
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/solution/ni-bo-lan-biao-da-shi-qiu-zhi-by-leetcod-wue9/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
lt.227. 基本计算器 ||
[案例需求]
[思路分析一, 单栈解法]
[代码实现]
class Solution {
public int calculate(String s) {
Deque<Integer> stack = new LinkedList<Integer>();
char preSign = '+';
int num = 0;
int n = s.length();
for (int i = 0; i < n; ++i) {
if (Character.isDigit(s.charAt(i))) {
num = num * 10 + s.charAt(i) - '0';
}
if (!Character.isDigit(s.charAt(i)) && s.charAt(i) != ' ' || i == n - 1) {
switch (preSign) {
case '+':
stack.push(num);
break;
case '-':
stack.push(-num);
break;
case '*':
stack.push(stack.pop() * num);
break;
default:
stack.push(stack.pop() / num);
}
preSign = s.charAt(i);
num = 0;
}
}
int ans = 0;
while (!stack.isEmpty()) {
ans += stack.pop();
}
return ans;
}
}
[思路分析二, 双栈解法]
[代码实现]
lt.224. 基本计算器
[案例需求]
[思路分析]
[代码实现]
计算器实现是真的很恶心啊, 有没有一种方法通杀?
- 题解
- 其实文章最开始贴的一个笔者的旧文就有这种写法, 大致思路就是把给定的前缀表达式转换为后缀表达式, 然后再进行计算, 计算过程就是把运算符存储在符号栈中, 另外遇到左括号 ( 直接压入符号栈, 遇到右括号 ) 不断的出符号栈, 并和数字栈中出栈的两个数进行计算;
- 在往符号栈中添加运算符时, 我们还需要维护一个运算符的优先级;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律