力扣150(java)-逆波兰表达式求值(中等)
题目:
根据 逆波兰表示法,求表达式的值。
有效的算符包括 +、-、*、/ 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
注意 两个整数之间的除法只保留整数部分。
可以保证给定的逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。
示例 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 + * 也可以依据次序计算出正确结果。
- 适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中
来源:力扣(LeetCode)
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路:
1.利用栈后进先出的特点进行模拟:
- 遍历输入的字符串;
- 遇到整数时,直接将整数压入栈中;
- 遇到操作符(+ - * /),就从栈顶依次弹出两个操作数与此时的操作符进行运算,并将运算结果作为操作数压入栈中,进行下一轮循环;
- 数组遍历完后,栈顶元素就是表达式的值,直接弹出栈顶元素进行返回即可。
代码:
1 class Solution { 2 public int evalRPN(String[] tokens) { 3 Deque<Integer> stack = new ArrayDeque<>(); 4 for(String s : tokens){ 5 if(s.equals("+")){ 6 int num1 = stack.pop(); 7 int num = num1 +stack.pop(); 8 stack.push(num); 9 }else if(s.equals("-")){ 10 int num1 = stack.pop(); 11 int num = stack.pop() - num1; 12 stack.push(num); 13 }else if(s.equals("*")){ 14 int num1 = stack.pop(); 15 int num = num1 * stack.pop(); 16 stack.push(num); 17 }else if(s.equals("/")){ 18 int num1 = stack.pop(); 19 int num = stack.pop() / num1; 20 stack.push(num); 21 }else{ 22 stack.push(Integer.parseInt(s)); 23 } 24 } 25 return stack.pop(); 26 } 27 }
今天终于自己独立的看题目解出一道题并通过啦~
2023-05-24:
1 class Solution { 2 public int evalRPN(String[] tokens) { 3 Stack<Integer> stack = new Stack<>(); 4 for (String s : tokens){ 5 if (s.equals("+")){ 6 stack.push(stack.pop() + stack.pop()); 7 }else if (s.equals("-")){ 8 stack.push(-stack.pop() + stack.pop()); 9 }else if (s.equals("*")){ 10 stack.push(stack.pop() * stack.pop()); 11 }else if (s.equals("/")){ 12 int temp1 = stack.pop(); 13 int temp2 = stack.pop(); 14 stack.push(temp2 / temp1); 15 }else { 16 stack.push(Integer.valueOf(s)); 17 } 18 } 19 return stack.pop(); 20 } 21 }
小知识:
Integer.valueOf(s)在Integer.parseInt(s)的计算的基础上,将int类型的数值转换成了Integer类型,就是基本类型的包装类型是引用类型。所以单单为了得到一个int值,就用Integer.parseInt(s)就行了。如果为了得到包装类型就用Integer.valueOf(s)。毕竟缓存了一部分数值,可以加强点儿性能。本题栈中存放是类型就是Integer,故这里需要使用Integer.valueOf(s)。
2.利用数组存放操作数来模拟栈实现:
思路跟上面一致,有几个可以改善的地方:
- 数组的长度可以设置成 tokens.length / 2 + 1,因为每两个操作数只需要一个操作符,操作数只需要 tokens.length / 2 + 1个长度就可以,例如[4,13,5]三个操作数只需要两个位置就可以了。
- 使用switc..case 代替 if...else if ...else 效率更优化
代码:
1 class Solution { 2 public int evalRPN(String[] tokens) { 3 int[] numStack = new int[tokens.length /2 + 1]; 4 int index = 0; 5 for(String s : tokens){ 6 switch(s){ 7 case "+": 8 numStack[index - 2] += numStack[--index]; 9 break; 10 case "-": 11 numStack[index - 2] -= numStack[--index]; 12 break; 13 case "*": 14 numStack[index - 2] *= numStack[--index]; 15 break; 16 case "/": 17 numStack[index - 2] /= numStack[--index]; 18 break; 19 default: 20 numStack[index++] = Integer.parseInt(s); 21 } 22 } 23 return numStack[0]; 24 } 25 }