题目
根据逆波兰表示法,求该后缀表达式的计算结果。
有效的算符包括
+
、
−
、
∗
、
/
+、-、*、/
+、−、∗、/ 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
说明:
整数除法只保留整数部分。
给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为
0
0
0 的情况。
示例 1:
输入:
t
o
k
e
n
s
=
[
"
2
"
,
"
1
"
,
"
+
"
,
"
3
"
,
"
∗
"
]
tokens = ["2","1","+","3","*"]
tokens=["2","1","+","3","∗"] 输出:
9
9
9 解释:该算式转化为常见的中缀算术表达式为:
(
(
2
+
1
)
∗
3
)
=
9
((2 + 1) * 3) = 9
((2+1)∗3)=9
示例 2:
输入:
t
o
k
e
n
s
=
[
"
4
"
,
"
13
"
,
"
5
"
,
"
/
"
,
"
+
"
]
tokens = ["4","13","5","/","+"]
tokens=["4","13","5","/","+"] 输出:
6
6
6 解释:该算式转化为常见的中缀算术表达式为:
(
4
+
(
13
/
5
)
)
=
6
(4 + (13 / 5)) = 6
(4+(13/5))=6
示例 3:
输入:
t
o
k
e
n
s
=
[
"
10
"
,
"
6
"
,
"
9
"
,
"
3
"
,
"
+
"
,
"
−
11
"
,
"
∗
"
,
"
/
"
,
"
∗
"
,
"
17
"
,
"
+
"
,
"
5
"
,
"
+
"
]
tokens = ["10","6","9","3","+","-11","*","/","*","17","+","5","+"]
tokens=["10","6","9","3","+","−11","∗","/","∗","17","+","5","+"] 输出:
22
22
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
((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
((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
−
4
∗
6
(2 + 1)* 3 - 4 * 6
(2+1)∗3−4∗6 ,我们按照左优先的原则,如果两个运算符同级,那么左侧的运算符进行优先运算
我们首先给每个运算符进行优先级编号,按照左优先原则我们得到上面的结果。同时从左向右依次读取,将运算的两数的中缀顺序改为后缀顺序。
最后我们可以得到上面的结果,按照左优先原则得到的结果的运算符也是按照从小到大顺序的。
- 中缀表达式 》》后缀表达式(机算)
对于计算机来说,中缀表达式转换成为后缀表达式自有一套自己的方式,首先创建一个栈来存储运算符,然后从左向右一次读取。
操作数:对于操作数,我们不用进行操作,直接取出。
运算符:对于运算符,我们依次弹出栈中优先级高于或等于自己(左优先原则)的运算符,直到遇到
"
(
"
"("
"(" 或者栈空为止,不包含
"
(
"
"("
"(" 。
界限符:对于界限符来说,遇到
"
(
"
"( "
"("直接存入栈中,遇到
"
)
"
")"
")"一次弹出栈中所有的运算符,直到遇到
"
(
"
"( "
"("为止, 包含
"
(
"
"("
"(" 。
如上图所示,我们在遇到
"
)
"
")"
")"运算符时,我们将其一次弹出,但是由于界限符在后缀表达式中不改变运算结果,因此不需要加上。
当我们压入
"
−
"
" - "
"−" 时,由于栈中的
"
∗
"
" * "
"∗" 的优先级高于它,因此我们将其弹出。
在最后全部读取完成的时候,我们将栈中的操作符依次弹出,最后得到的结果与上面手算的相同。
- 后缀表达式计算(手算)
后缀表达式计算的方式其实很简单,从左向右依次读取,遇到运算数就放入中缀表达式中,遇到操作符就将其前面的两个运算数进行计算。
当我们读取到
"
+
"
" + "
"+" 时,我们将前面的操作数进行运算,并且在之后的运算中视为一个数。
按照这样的方式继续从左向右读取。
最终我们得到转换成功的中缀表达式并可以进行计算。
- 后缀表达式计算(机算)
我们可以按照上面计算的方式进行运算,不过需要创建一个栈用来对于运算数进行存储。
当我们读取到
"
+
"
" + "
"+" 时,我们可以将栈中存储的前两个数字弹出进行运算,然后将运算结果存入重新栈中。
最终我们得到上图所示的结果。
- 前缀表达式
前缀表达式的所有转换和运算都与后缀相同,只不过是将从左向右换成了从右向左和右优先原则,存入时也是从右向左。
在计算优先级的时候需要知道,是在从左向右读的时候同时有右优先原则,而不是直接在中间选一个优先级最高的。
而不是直接选取中间括号的优先级最高
- 中缀表达式的计算
中缀表达式的计算需要两个栈的辅助,一个在中缀表达式转换成后缀表达式中用来存储运算符,另一个在转换完的后缀表达式的运算中用来存储操作数。
此时我们因该已经知道了这道题的计算方法了,维护一个栈用来存储运算数。
代码:
class Solution {
public:
int evalRPN(vector<string>& tokens) {
int len = tokens.size();
stack<int> expression;
for(int i = 0; i < len; i++){
if(tokens[i] == "+"){
int first = expression.top();
//pop函数是没有返回值的,要先使用top(),在使用pop()。
expression.pop();
int second = expression.top();
expression.pop();
expression.push(first + second);
continue;
}
if(tokens[i] == "*"){
int first = expression.top();
expression.pop();
int second = expression.top();
expression.pop();
expression.push(first * second);
continue;
}
if(tokens[i] == "-"){
int first = expression.top();
expression.pop();
int second = expression.top();
expression.pop();
expression.push(second - first);
continue;
}
if(tokens[i] == "/"){
int first = expression.top();
expression.pop();
int second = expression.top();
expression.pop();
expression.push(second / first);
continue;
}
//字符串转换成为整数类型。还可以使用stringstream
// stringstream ss;
// ss << tokens[i];
// int num;
// ss >> num;
int num = stoi(tokens[i]);
expression.push(num);
}
int res = expression.top();
return res;
}
};