【Question recording】Stack queue practice

1. Minimal stack

Topic Link: 155. Minimal Stack - LeetCode

Question stem:

Design a stack that supports push, pop, top operations, and can retrieve the smallest element in constant time.

Implement the MinStack class:

  • MinStack() Initializes a stack object.
  • void push(int val) pushes the element val onto the stack.
  • void pop() Removes the element at the top of the stack.
  • int top() Gets the top element of the stack.
  • int getMin() Gets the smallest element in the stack.

Example:

输入:
[“MinStack”,“push”,“push”,“push”,“getMin”,“pop”,“top”,“getMin”]
[[],[-2],[0],[-3],[],[],[],[]]

输出:
[null,null,null,null,-3,null,0,-2]

Explanation:
MinStack minStack = new MinStack();
myStack.push(-2);
myStack.push(0);
myStack.push(-3);
minStack.getMin(); --> returns -3.
myStack.pop();
myStack.top(); --> 内容 0.
minStack.getMin(); --> returns -2.

Topic analysis:

In order to be able to find the minimum value in the current stack within the time complexity of O(1), we can think of using two stacks, one stack normally stores data (data stack), and the other stack stores the minimum value in the current stack (minimum stack) so that the minimum can be found directly.

Every time data is pushed, the data station pushes normally, and the minimum stack judges the size of the minimum value and the current value before the push. If the push data is smaller than the top of the minimum stack, then the minimum stack pushes the current value, otherwise, it pushes the top value of the stack.

image-20230426101739729

In fact, if most of the data pushed into the stack is greater than the current minimum value, many identical and continuous numbers will appear in the minimum stack, which is a great waste of space. Therefore, we can consider modifying the push of the minimum stack The rule is that only when the newly pushed data is smaller than the current minimum value, it is put into the minimum stack , so that the data in the minimum stack will not have this kind of redundancy.

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-4feFqUnf-1682496626758)(null)]

Code:

//解法一:
class MinStack {
    
    
public:
    MinStack() {
    
    //这里默认构造函数就不用实现了,因为在这里成员变量会走初始化列表,在初始化列表这里会自动调用成员变量类型的默认构造函数
        
    }    
    void push(int val) {
    
    
        _st.push(val);
        if(_minst.empty() || val <= _minst.top())
        {
    
    
            _minst.push(val);
        }
    }    
    void pop() {
    
    
        if(_st.top() == _minst.top())
        {
    
    
            _minst.pop();
        }
        _st.pop();
    }   
    int top() {
    
    
        return _st.top();
    }
    int getMin() {
    
    
        return _minst.top();
    }
    
    stack<int> _st;
    stack<int> _minst;
};

image-20230426100739132

2. Reverse Polish expressions

Topic Link: 150. Reverse Polish Expression Evaluation - LeetCode

Question stem:

You are given an array of strings tokensrepresenting an arithmetic expression 逆波兰表示法expressed .

Please calculate this expression. Returns an integer representing the value of the expression.

Notice:

  • Valid operators are '+', '-', '*'and '/'.
  • Each operand (operand) can be an integer or another expression.
  • Division between two integers always truncates towards zero .
  • The expression does not contain division by zero.
  • The input is an arithmetic expression represented according to Reverse Polish Notation.
  • The answer and all intermediate calculation results can be represented by 32-bit integers.

Example 1:

Input: tokens = ["2", "1", "+", "3", "*"]
Output: 9
Explanation: This formula is transformed into a common infix arithmetic expression: ((2 + 1) * 3) = 9
Example 2:

Input: tokens = ["4", "13", "5", "/", "+"]
Output: 6
Explanation: This formula is transformed into a common infix arithmetic expression: (4 + (13 / 5 )) = 6
Example 3:

Input: tokens = ["10", "6", "9", "3", "+", "-11", " ","/", "", "17", "+", " 5 ", "+"]
Output: 22
Explanation: This formula is transformed into a common infix arithmetic expression:
((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

Topic analysis:

For the calculation of the reverse Polish expression, we traverse in order to find the first operator, and then take out the first two operands for calculation. In this way, we can think of using the stack to store data. When the operator reaches the operator, two elements are popped out for operation

image-20230426104416509

Code:

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();
    }
};

image-20230426095455573

Expand knowledge: infix expressions and postfix expressions

An expression is composed of operands and operators. The expressions we generally see usually put the operator between the two operands. This kind of expression that puts the operator in the middle is called an infix expression . , this expression is friendly to humans, but not so friendly to computers. Polish mathematician Jan Lukasiewicz proposed another mathematical representation, which has two representations: the operator is written before the operand , which is called Polish Expression (Polish Expression) or prefix expression (Prefix Expression), such as + AB; Write the operator after the operand , called Reverse Polish Expression (Reverse Polish Expression) or Suffix Expression (Suffix Expression), such as AB+. The reverse Polish expression mentioned in the above question is the postfix expression

Here is the algorithm idea of ​​converting infix to suffix:

  1. create stack
  2. Get infix expressions in order from left to right
    • digital direct output
    • operator
      • Situation 1: When the left parenthesis is encountered, it is directly pushed onto the stack, and when the right parenthesis is encountered, all the operators pushed onto the stack after the left parenthesis in the stack are popped and output, and the left parenthesis is popped out of the stack but not output.
      • Case 2: The multiplication and division signs are directly pushed onto the stack until an operator with a lower priority is encountered, and the stack is popped in turn.
      • Situation 3: When encountering a plus sign and a minus sign, if the stack is empty at this time, it will be directly pushed onto the stack, otherwise, the operators with higher priority in the stack will be popped off the stack in turn (note: the plus sign and the minus sign belong to the same priority, So the stack is also popped in turn) until the stack is empty or the left parenthesis is encountered, stop popping the stack. (Because the left parenthesis will only pop up when it matches the right parenthesis).
      • Situation 4: After the acquisition is complete, the remaining operation symbols in the stack are popped and output in turn

3. Stack push and pop sequence

Topic Link: Stack Push and Pop Sequence

Question stem:

Input two integer sequences, the first sequence represents the push order of the stack, please judge whether the second sequence may be the pop order of the stack. Assume that all numbers pushed onto the stack are unequal. For example, the sequence 1, 2, 3, 4, 5 is the push sequence of a certain stack, and the sequence 4, 5, 3, 2, 1 is a pop sequence corresponding to the push sequence, but 4, 3, 5, 1, 2 It cannot be the pop sequence of the push sequence.

  1. 0<=pushV.length == popV.length <=1000
  2. -1000<=pushV[i]<=1000
  3. All numbers of pushV are different

Example 1

Input: [1,2,3,4,5],[4,5,3,2,1]

return value: true

Explanation: You can pass push(1)=>push(2)=>push(3)=>push(4)=>pop()=>push(5)=>pop()=>pop()=>pop ()=>pop()
to get the sequence [4,5,3,2,1] and return true

Example 2

Input: [1,2,3,4,5],[4,3,5,1,2]

return value: false

Explanation: Due to the push order of [1,2,3,4,5] and the pop order of [4,3,5,1,2], it is required that 4, 3, 5 must be pushed in before 1, 2, And 1 and 2 cannot be popped up, but in such a pressing order, 1 cannot be popped up before 2, so if it cannot be formed, return false

Topic analysis:

For this kind of topic, if we want to brute force exhaustively, the complexity is indeed a bit too high, so now I have an idea whether we can simulate the operation of the stack and compare it with the pop-up sequence

First create a stack, then traverse the data in pushV, and push the stack, and then judge whether the data on the top of the stack is equal to the current data in popV, if they are equal, pop the stack, otherwise continue to push into the stack, if after traversing pushV, the stack If it is empty, it means that the popV sequence is available, return true, otherwise return false.

Code:

class Solution {
    
    
public:
    bool IsPopOrder(vector<int> pushV,vector<int> popV) {
    
    
        stack<int> st;
        int i = 0;
        for(auto& e : pushV)
        {
    
    
            st.push(e);
            while(!st.empty() && (st.top() == popV[i]))
            {
    
    
                st.pop();
                ++i;
            }
        }
        return st.empty();
    }
};

image-20230426105255229

4. Stack implements queue

Topic link: 232. Implementing queues with stacks - LeetCode

Question stem:

Please use only two stacks to implement a first-in-first-out queue. The queue should support all operations supported by general queues (push, pop, peek, empty):

Implement the MyQueue class:

void push(int x) pushes element x to the end of the queue
int pop() removes from the beginning of the queue and returns the element
int peek() returns the element at the beginning of the queue
boolean empty() returns true if the queue is empty; otherwise, Return false
Description:

You can only use standard stack operations -- that is, only push to top, peek/pop from top, size, and is empty operations are legal.
Your language may not support stacks. You can use list or deque (double-ended queue) to simulate a stack, as long as it is a standard stack operation.

Example 1:

Input:
["MyQueue", "push", "push", "peek", "pop", "empty"]
[[], [1], [2], [], [], []] Output
:
[null, null, null, 1, 1, false]

解释:
MyQueue myQueue = new MyQueue();
myQueue.push(1); // queue is: [1]
myQueue.push(2); // queue is: [1, 2] (leftmost is front of the queue)
myQueue.peek(); // return 1
myQueue.pop(); // return 1, queue is [2]
myQueue.empty(); // return false

Topic analysis:

According to the requirements of the topic, two stacks are used to implement a queue. Both the stack and the queue are container adapters, but the adapter interfaces provided are different. The stack is LIFO, and the queue is FIFO, so we use two stacks to implement the queue and only need to control the way of entering and exiting the queue.

Here we use two stacks, which we named st_push and st_pop respectively. For the operation of entering the queue, we push the value to the st_push stack. For the operation of dequeuing, we only output the elements in the st_pop stack , and then at the right time, the The elements in the st_push stack are transferred to the st_pop stack. Note here that every time you convert, you must convert all the elements in the push stack to the pop stack, and you can only convert when the pop stack is empty , otherwise the data order will be messed up.

image-20230426113433998

Code:

class MyQueue {
    
    
public:
    MyQueue() {
    
    //这里默认构造函数就不用实现了,因为在这里成员变量会走初始化列表,在初始化列表这里会自动调用成员变量类型的默认构造函数

    }
    void push(int x) {
    
    
        st_push.push(x);
    }    
    void conversion()//st_push ==> st_pop
    {
    
    
        if(st_pop.empty())
        {
    
    
            while(!st_push.empty())
            {
    
    
                st_pop.push(st_push.top());
                st_push.pop();
            }
        }
    }
    int pop() {
    
    
        conversion();//当pop栈为空时,从push栈中导入所有元素
        int ret = st_pop.top();
        st_pop.pop();
        return ret;
    }    
    int peek() {
    
    
        conversion();
        return st_pop.top();
    }  
    bool empty() {
    
    
        return st_pop.empty() && st_push.empty();
    }
    
    stack<int> st_push;
    stack<int> st_pop;
};

image-20230426113936568

5. Queue implementation stack

Topic link: 225. Implementing a stack with a queue - LeetCode

Question stem:

Please use only two queues to implement a last-in-first-out (LIFO) stack, and support all four operations (push, top, pop, and empty) of a normal stack.

Implement the MyStack class:

void push(int x) pushes the element x onto the top of the stack.
int pop() removes and returns the top element of the stack.
int top() Returns the top element of the stack.
boolean empty() Returns true if the stack is empty; otherwise, returns false.

Notice:

You can only use the basic operations of the queue - that is, push to back, peek/pop from front, size and is empty.
Your language may not support queues. You can use list (list) or deque (double-ended queue) to simulate a queue, as long as it is a standard queue operation.

Example:

Input:
["MyStack", "push", "push", "top", "pop", "empty"]
[[], [1], [2], [], [], []]
Output:
[null, null, null, 2, 2, false]

Explanation:
MyStack myStack = new MyStack();
myStack.push(1);
myStack.push(2);
myStack.top(); // returns 2
myStack.pop(); // returns 2
myStack.empty(); // return False

Topic analysis:

Same as the previous question, we only need to control the order of stacking and popping

Since you want to get the elements at the end of the queue if you want to get out of the stack, you need to get out the other elements in the queue before you can get the elements at the end of the queue. At this time, the elements that are out are stored in another queue, and the order of entering the queue is also fixed. Yes, so the order of the elements in the queue remains unchanged, so when inserting elements, continue to insert in the non-empty queue

image-20230426155014066

Code:

class MyStack {
    
    
public:
    queue<int> q1;
    queue<int> q2;
    MyStack() {
    
    //这里默认构造函数就不用实现了,因为在这里成员变量会走初始化列表,在初始化列表这里会自动调用成员变量类型的默认构造函数

    }
    void push(int x) {
    
    //这里在结构上保证必须有一个队列是空的
        if (q1.empty())
            q2.push(x);
        else
            q1.push(x);
    }
    int pop() {
    
    //在需要pop的时候将非空队列的前n个值转换到空队列中,然后pop非空队列
        if (q2.empty())
        {
    
    
            swap(q1, q2);
        }
        //此时q1为空,q2有值
        int size = q2.size();
        for (size_t i = 0; i < size - 1; ++i)
        {
    
    
            q1.push(q2.front());
            q2.pop();
        }
        int ret = q2.front();
        q2.pop();
        return ret;
    }
    int top() {
    
    //非空队列中的最后一个元素即是栈顶元素
        if (q1.empty())
        {
    
    
            return q2.back();
        }
        else
            return q1.back();
    }
    bool empty() {
    
    
        return q1.empty() && q2.empty();
    }
};

image-20230426154501554

Guess you like

Origin blog.csdn.net/weixin_63249832/article/details/130388566