【stack题解】逆波兰表达式求值 | 用队列实现栈

逆波兰表达式求值

力扣(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 / +

当从左往右读到 / 时,要把前两个操作数取出来运算,这种结构,让我们想到了

【stack题解】逆波兰表达式求值 | 用队列实现栈_第1张图片

实现

class Solution {
public:
    int evalRPN(vector& tokens) {
        stack 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的数。

【stack题解】逆波兰表达式求值 | 用队列实现栈_第2张图片

class MyStack {
public:
    queue 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 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();
    }
};

你可能感兴趣的:(c++,leetcode)