leetcode150逆波兰表达式传送门
题目:根据逆波兰表示法,求表达式的值。有效的运算符包括 +, -, *, / 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。说明: 1.整数除法只保留整数部分。2.表达式总会得出有效数值且不存在除数为 0 的情况。
输入: ["2", "1", "+", "3", "*"]
输出: 9 解释: ((2 + 1) * 3) = 9
输入: ["4", "13", "5", "/", "+"]
输出: 6 解释: (4 + (13 / 5)) = 6
- 遇到数字, 把数字入栈
- 否则 遇到运算符, 栈中弹出来两个数 (第二个数是在运算符前) 根据运算符进行运算, 得到的结果重新入栈
这里主要是根据不同运算符,对栈顶操作比较巧妙
public int evalRPN(String[] tokens) {
Stack<Integer> stack = new Stack<>();
for (String s : tokens) {
if (s.equals("+")) {
stack.push(stack.pop() + stack.pop());
} else if (s.equals("-")) {
stack.push(-stack.pop() + stack.pop()); // 栈顶是减数,取反
} else if (s.equals("*")) {
stack.push(stack.pop() * stack.pop());
} else if (s.equals("/")) {
int num = stack.pop(); // 先临时保存栈顶(除数)
stack.push(stack.pop() / num);
} else { //数字, 注意负数如-11这种情况,所以不能用s[0]>=’0’&&s[0]<=’9’判断数字
stack.push(Integer.parseInt(s));
}
}
return stack.pop();
}
题目: 实现一个基本的计算器来计算一个简单的字符串表达式的值。
可以假设所给定的表达式都是有效的。
字符串表达式仅包含非负整数,+, - ,*,/ 四种运算符和空格。
整数除法仅保留整数部分。
输入: " 3+5 / 2 "
输出: 5
方法1. 传统数字栈+符号栈
一定要注意过滤空格!
public int calculate(String s) {
Stack<Integer> stack = new Stack<Integer>(); // 数字栈
Stack<Character> chStack = new Stack<Character>();//运算符栈
int sum = 0; // 多个字符拼接成一个数字
for (int i = 0; i < s.length(); ++i) {
char ch = s.charAt(i);
if (ch <= '9' && ch >= '0') { // 累计拼接字符数字
sum = sum * 10 + (ch - '0');
} else if (ch != ' '){ // 过滤掉空格 只剩运算符
stack.push(sum); // 遇到字符 把前面拼接的数字入栈
sum = 0; // sum置0
// 栈不空 或者 当前运算符优先级 <= 栈顶运算符优先级
while (!chStack.empty() &&
isBigger(chStack.peek(), ch)) {
// 把数字栈顶两个数值弹出 进行运算
compute(stack, chStack.pop());
}
chStack.push(ch); // 当前运算符入 运算符栈
}
}
stack.push(sum); // 最后一个数字 在for里计算之后没有入栈
while (!chStack.empty()) { // 最后计算剩下的数
compute(stack, chStack.pop());
}
return stack.pop();
}
// 根据输入运算符ch 计算stack栈顶两个数
void compute(Stack<Integer> stack, char ch) {
if (ch == '+') {
stack.push(stack.pop() + stack.pop());
} else if (ch == '-') { // 栈顶是减数,取反
stack.push(-stack.pop() + stack.pop());
} else if (ch == '*') {
stack.push(stack.pop() * stack.pop());
} else if (ch == '/') {
int num = stack.pop(); // 先临时保存栈顶(除数)
stack.push(stack.pop() / num);
}
}
// 运算符a的优先级 >= b的优先级
boolean isBigger(char a, char b) {
if (a == '/' || a == '*') return true;
if (b == '+' || b == '-') return true; // a b 是 +或者-
return false; // a 是+或- b是*或者/
}
方法2. 优化,只用数字栈
符号栈用一个变量sign代替了,只存储上一个符号,
注意,sign是当前数字前面的那个符号
比如:2+3*6
遇到*的时候,这时判断sign是+,那么把3直接入栈,
因为前面是+,3后面运算优先级不会比它低,没有影响;
而当遇到*,/时,可以直接计算了,因为后面的优先级不会比它高了
同时,加 减 乘 除 空格 的ASCII码都小于'0',可以做判断条件
public int calculate(String s) {
if (s.length() == 0) return 0;
Stack<Integer> numStk = new Stack<>();
char sign = '+';// 保存上一个符号,初始为 +
int sum = 0;// 保存当前数字,如:12是两个字符,需要进位累加
for (int i = 0; i < s.length(); ++i) {
char cur = s.charAt(i);
if (cur >= '0') // +,-,*,/, 空格 ASCII码都<'0',可省略其他条件
sum = sum * 10 - '0' + cur; // 先减'0',防止溢出
// 注意!这里不能用else if,
// 因为i到s末尾的时候,cur还是数字,不会进到下面计算
// 同时,这里不能省略i到末尾的判断,
// 如果要拿到for外面计算最后一个数字sum
// 还要判断sign是什么,
//进行最后一个sum的计算,不是直接把sum加入到numStk里
if ((cur != ' ' && cur < '0') || i == s.length() - 1){
// 注意这里判断的是sign:当前数字sum的前面的符号,而不是cur
if (sign == '+') numStk.push(sum);
else if (sign == '-') numStk.push(-sum);
else if (sign == '*') numStk.push(numStk.pop() * sum);
else if (sign == '/') numStk.push(numStk.pop() / sum);
sign = cur; // 符号更新
sum = 0;// 数字清零
}
}
sum = 0;
// 将栈内剩余数字累加,即为结果
while (!numStk.empty()) sum += numStk.pop();
return sum;
}