逆波兰表达式求值
力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
给你一个字符串数组 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 + 2 ) * ( 3 + 4 ) 。 该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * ) 。 逆波兰表达式主要有以下两个优点:
去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。 适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中
分析
理解逆波兰表达式:
逆波兰表达式,是一种后缀表达式。
我们平时写的算式是这样的:1+10/5,这是一种中缀表达式,即运算符在中间,操作数在两边。
而中缀表达式并不适合计算机去计算,计算机是从左往右读取值的:1 + 10 / 5,这样计算的结果就是11/5=2。
为了贴合计算机的读取方式,我们就可以用后缀表达式,即操作数在前,相对顺序不变;运算符按照优先级的顺序,排列在后。
1+10/5改成后缀表达式为:1 10 5 / +
当从左往右读到 / 时,要把前两个操作数取出来运算,这种结构,让我们想到了栈。
实现
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<int> st;
for(auto str:tokens){
if(str=="+"||str=="-"||str=="*"||str=="/"){
int right=st.top();
st.pop();
int left=st.top();
st.pop();
switch(str[0]){
case '+':
st.push(left+right);
break;
case '-':
st.push(left-right);
break;
case '*':
st.push(left*right);
break;
case '/':
st.push(left/right);
break;
}
}
else{
st.push(stoi(str));
}
}
return st.top();
}
};
用队列实现栈
力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。
实现 MyStack 类:
void push(int x) 将元素 x 压入栈顶。 int pop() 移除并返回栈顶元素。 int top() 返回栈顶元素。 boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。
注意:
你只能使用队列的基本操作 —— 也就是 push to back、peek/pop from front、size 和 is empty 这些操作。 你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。
示例:
输入:["MyStack", "push", "push", "top", "pop", "empty"]
[[], [1], [2], [], [], []]
输出:[null, null, null, 2, 2, false]
解释:
MyStack myStack = new MyStack();
myStack.push(1);
myStack.push(2);
myStack.top(); // 返回 2
myStack.pop(); // 返回 2
myStack.empty(); // 返回 False
提示:
1 <= x <= 9 最多调用100 次 push、pop、top 和 empty 每次调用 pop 和 top 都保证栈不为空
进阶:你能否仅用一个队列来实现栈。
初级:用两个栈实现
两个栈q1、q2。当q1不为空,q2为空时,入数据就直接往q1入。删数据时,先把q1中不删的数据都入到q2中,再删q1的数。
class MyStack {
public:
queue<int> q1,q2;
MyStack() {
}
void push(int x) {
if(!q1.empty()){
q1.push(x);
}
else{
q2.push(x);
}
}
int pop() {
if(q1.empty()){
int num=q2.size()-1;
while(num--){
q1.push(q2.front());
q2.pop();
}
int ret=q2.front();
q2.pop();
return ret;
}
else{
int num=q1.size()-1;
while(num--){
q2.push(q1.front());
q1.pop();
}
int ret=q1.front();
q1.pop();
return ret;
}
}
int top() {
if(!q1.empty()){
return q1.back();
}
else{
return q2.back();
}
}
bool empty() {
return q1.empty()&&q2.empty();
}
};
进阶:用一个栈实现
这个方法非常巧妙。我们就用一个队列,插入就直接入队列;删除的话,把 末尾元素之前的全部元素 出队,再重新入队,这样,队列的首元素就是栈顶元素了。此时再pop。
class MyStack {
public:
queue<int> q;
MyStack() {
}
void push(int x) {
q.push(x);
}
int pop() {
int num=q.size()-1; //把末尾元素之前的元素 都重新入队列
while(num--){
q.push(q.front());
q.pop();
}
int ret=q.front(); //先记录栈顶元素,再删
q.pop();
return ret;
}
int top() {
return q.back();
}
bool empty() {
return q.empty();
}
};