给你一个字符串数组 tokens
,表示一个根据 逆波兰表示法 表示的算术表达式。
请你计算该表达式。返回一个表示表达式值的整数。
注意:
- 有效的算符为
'+'
、'-'
、'*'
和'/'
。 - 每个操作数(运算对象)都可以是一个整数或者另一个表达式。
- 两个整数之间的除法总是 向零截断 。
- 表达式中不含除零运算。
- 输入是一个根据逆波兰表示法表示的算术表达式。
- 答案及所有中间计算结果可以用 32 位 整数表示。
示例 1:
输入:tokens = ["2","1","+","3","*"] 输出:9 解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9
示例 2:
输入:tokens = ["4","13","5","/","+"] 输出:6 解释:该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6
示例 3:
输入:tokens = ["10","6","9","3","+","-11","*","/","*","17","+","5","+"] 输出:22 解释:该算式转化为常见的中缀算术表达式为: ((10 * (6 / ((9 + 3) * -11))) + 17) + 5 = ((10 * (6 / (12 * -11))) + 17) + 5 = ((10 * (6 / -132)) + 17) + 5 = ((10 * 0) + 17) + 5 = (0 + 17) + 5 = 17 + 5 = 22
提示:
1 <= tokens.length <= 104
tokens[i]
是一个算符("+"
、"-"
、"*"
或"/"
),或是在范围[-200, 200]
内的一个整数
逆波兰表达式:
逆波兰表达式是一种后缀表达式,所谓后缀就是指算符写在后面。
- 平常使用的算式则是一种中缀表达式,如
( 1 + 2 ) * ( 3 + 4 )
。 - 该算式的逆波兰表达式写法为
( ( 1 2 + ) ( 3 4 + ) * )
。
逆波兰表达式主要有以下两个优点:
- 去掉括号后表达式无歧义,上式即便写成
1 2 + 3 4 + *
也可以依据次序计算出正确结果。 - 适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中
就名字比较唬人,自己看代码吧,实在看不懂就留言或者私信,第一时间解答,我里面有个常数项的优化,面试基本不看,能看懂就看,看不懂就不看把,无所谓的,我就是看到超过20%多的人看不过去,改了一下
class Solution {
/**这狗屁名字真的是有点唬人,我简单解释一下:逆波兰表达式就是操作数在前,运算法在后的表达式
比如我们平时是1+2,逆波兰就是1 2 +
本题给出的所有的tokens里要么是操作数要么是操作符
我们判断如果是操作数就入栈,如果是操作符就把栈里的弹出计算 */
public int evalRPN2(String[] tokens) {
/**如果只有一个操作符,那它肯定是个数,直接转成int返回 */
if(tokens.length == 1) {
return Integer.parseInt(tokens[0]);
}
/**建立一个操作数栈,Integer类型,如果不是+ - * /就入栈
如果是就弹出求解*/
Stack<Integer> stack = new Stack<>();
for(String token : tokens) {
/**如果是操作符,弹出两个数计算 */
if(token.equals("+") || token.equals("-") || token.equals("*") || token.equals("/")) {
int result = calculate(token, stack.pop(), stack.pop());
/**计算完再放进去,最后从栈里取 */
stack.push(result);
} else {
/**数字直接入栈 */
stack.push(Integer.parseInt(token));
}
}
return stack.peek();
}
/**进行结算的函数*/
public int calculate(String operator, int num1, int num2) {
int result = 0;
/**这里要注意我们先弹出来的是num1,后弹出的是num2
加和乘无所谓,减和除的时候一定要注意num1在前面 */
switch(operator) {
case "+":
result = num1 + num2;
break;
case "-":
result = num2 - num1;
break;
case "*":
result = num1 * num2;
break;
case "/":
result = num2 / num1;
break;
}
return result;
}
/**唉,O(N)的时间复杂度打败那么点人,我擦,我要改造了,真觉得这些破玩意改造个常数时间有啥意义*/
public int evalRPN(String[] tokens) {
/**如果只有一个操作符,那它肯定是个数,直接转成int返回 */
if(tokens.length == 1) {
return Integer.parseInt(tokens[0]);
}
/**使用数组代替栈*/
int[] stack = new int[tokens.length];
int validLen = 0;
for(String token : tokens) {
/**如果是操作符,弹出两个数计算 */
if(token.equals("+") || token.equals("-") || token.equals("*") || token.equals("/")) {
int result = calculate(token, stack[--validLen], stack[--validLen]);
/**计算完再放进去,最后从栈里取 */
stack[validLen++] = result;
} else {
/**数字直接入栈 */
stack[validLen ++] = Integer.parseInt(token);
}
}
return stack[validLen - 1];
}
}