150. Evaluate Reverse Polish Notation
Evaluate the value of an arithmetic expression in Reverse Polish Notation.
Valid operators are +, -, *, /. Each operand may be an integer or another expression.
Note:
- Division between two integers should truncate toward zero.
- The given RPN expression is always valid. That means the expression would always evaluate to a result and there won’t be any divide by zero operation.
Example 1:
Input: ["2", "1", "+", "3", "*"]
Output: 9
Explanation: ((2 + 1) * 3) = 9
Example 2:
Input: ["4", "13", "5", "/", "+"]
Output: 6
Explanation: (4 + (13 / 5)) = 6
Example 3:
Input: ["10", "6", "9", "3", "+", "-11", "*", "/", "*", "17", "+", "5", "+"]
Output: 22
Explanation:
((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
题目背景(了解后缀表达式可以跳过): 题目描述了一种逆波兰表达式(也叫做后缀表达式),这种表达式和日常使用的表达式不同,一般人们习惯使用的表达式称作中缀表达式,顾名思义就是将操作符放到操作数的中间,比如(2 + 1) * 3
,而逆波兰表达式或者叫做后缀表达式则是将操作符放到操作数的后面比如中缀表达式1 + 2
转换为后缀表达式为1 2 +
。
后缀表达式比我们日常使用的中缀表达式有一个非常好的优点,就是在计算表达式的值的时候,不需要考虑运算符的优先级。如在程序中写下中缀表达式1 + 2 * 3
,编译器在计算时需要考虑加法和乘法的优先级,从而判断应该先执行乘法,但是实际上编译器会先将中缀表达式转化为后缀表达式: 1 2 3 * +
,(手动转换简单,参考百科,或者在这题不需要考虑,但是用程序转换不是一两句能说清,可以再写个博客讨论。。。)而后缀表达式1 2 3 * +
计算时不需要考虑优先级,只需要按照如下的思路进行,这也就是这个题的解题思路。
后缀表达式计算思路:后缀表达式计算主要需要使用栈,建立一个栈stk
。从左到右读表达式,如果读到操作数就将它压入栈stk
中,如果读到n元运算符(即需要参数个数为n的运算符)则取出由栈顶向下的n项操作数,按操作符运算,再将运算的结果代替原栈顶的n项,压入栈S中 。如果后缀表达式未读完,则重复上面过程,最后输出栈顶的数值则为结束(语言组织不行,参考百科)。
比如有后缀表达式["4", "13", "5", "/", "+"]
,计算时从左往右扫描整个表达式,设置一个栈stk
,当遇到数字时将数字压入栈中,在这个例子中,4,13,5
先后被压入栈stk
中,当遇到/
时,这是一个二元操作符,需要两个操作数,这时将栈stk
栈顶的两个元素弹出作为操作数,该例中将5,13
弹出栈,先出栈的元素5
作为右操作数(必须注意这个原则,否则减法除法会出错),计算表达式13 / 5
,并将计算结果2
压入栈stk
中,此时栈中有两个元素4,2
,继续扫描下一个元素,发现是运算符+
,将2,4
出栈,计算4 + 2
,并且将结果6
压入栈stk
,扫描完毕,最后返回栈stk
的栈顶元素即为表达式的值。
代码:
class Solution {
public:
int compute(int opd1, int opd2, string op)
{
if(op == "+")
return opd1 + opd2;
else if(op == "-")
return opd1 - opd2;
else if(op == "*")
return opd1 * opd2;
else// if(op == "/")
return opd1 / opd2;
}
int evalRPN(vector<string>& tokens) {
stack<int> stk_1;//操作数栈
for(int i = 0; i<tokens.size(); i++)
{
//cout<<tokens[i]<<endl;
if ( isdigit(tokens[i][0]) || tokens[i].length()>1 )//遇到了数字直接入栈
{
stk_1.push( stoi(tokens[i]) );//c++11 string to integer
}
else//遇到了操作符
{
string op = tokens[i];//栈顶元素
int opd2 = stk_1.top();stk_1.pop();//注意先出栈的是右操作数
int opd1 = stk_1.top();stk_1.pop();
int result = compute(opd1, opd2, op);
stk_1.push(result);//计算结果入操作数栈
}
}//end for loop
return stk_1.top();
}
};