力扣日记10.9【栈与队列篇】用队列实现栈

力扣日记:【栈与队列篇】用队列实现栈

日期:2023.10.9
参考:代码随想录、力扣

225. 用队列实现栈

题目描述

难度:简单

请你仅使用两个队列实现一个后入先出(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 都保证栈不为空

进阶:你能否仅用一个队列来实现栈。

题解

class MyStack {
#define SOLUTION 2 
public:
#if SOLUTION == 1
    queue<int> q1;
    queue<int> q2;
    MyStack() {
        
    }
    
    void push(int x) {
        q1.push(x);
    }
    
    int pop() {
        // 只有q1为空时,才能从q2弹出
        // 否则从q1弹出
        if (!q1.empty()) {
            // 如果q1非空,则将q1的元素转移至q2直到q1只剩1个元素
            while (q1.size() > 1) {
                q2.push(q1.front());
                q1.pop();
            }
            // q1.size() == 1
            int res = q1.front();
            q1.pop();
            return res;
        } else if (!q2.empty()){
            // q1 为空,考虑从q2弹出
            while (q2.size() > 1) {
                q1.push(q2.front());
                q2.pop();
            }
            // q2.size() == 1
            int res = q2.front();
            q2.pop();
            return res;
        }
        return -1;
    }
    
    int top() {
        // 复用 pop() 代码

        int res = this->pop();
        q1.push(res);   // q1 q2 应该都可以
        return res;
    }
    
    bool empty() {
        return q1.empty() && q2.empty();
    }
#elif SOLUTION == 2
    // 优化:使用一个队列实现栈
    // 每次要弹出“栈顶元素”(即队尾元素)时,都将队列中除最后一个元素的其他元素弹出并放到队尾,再将头一个元素弹出,即可实现栈
    queue<int> q;
    MyStack() {
        
    }
    
    void push(int x) {
        q.push(x);
    }
    
    int pop() {
        int size = q.size();
        while (size > 1) {
            q.push(q.front());
            q.pop(); // 将元素弹出并放到队尾
            size--;
        }
        // 此时原先的队尾元素到第一个了
        int res = q.front();
        q.pop();
        return res;
    }
    
    int top() {
        return q.back(); // 队列有back()方法可以取队尾元素
        
        // 服用top()
        // int res = this->pop();
        // q.push(res);
        // return res;
    }
    
    bool empty() {
        return q.empty();
    }
#endif
};

/**
 * Your MyStack object will be instantiated and called as such:
 * MyStack* obj = new MyStack();
 * obj->push(x);
 * int param_2 = obj->pop();
 * int param_3 = obj->top();
 * bool param_4 = obj->empty();
 */

复杂度

  • 时间复杂度: pop为O(n)(如果top()不用back()方法也为O(n)),其他为O(1)
  • 空间复杂度: O(n)

思路总结

  • 队列的基本方法
    • push()
    • pop()
    • top()
    • back()
    • empty()
  • 使用两个队列实现:
    • 不同于用栈实现队列,用队列实现栈中两个队列并不是一个作为输入一个作为输出,而是q1相对于q2有一定的优先级(每次判断都是先考虑q1,如当q1为空时才考虑从q2弹出)。
    • 然后用模拟的方法即可(画示意图)
    • 代码随想录的方法是直接将q2当作备份(每次q1弹出队尾元素时先放到q2,然后弹出队尾元素后就将q2清空,即重新全部放回q1)
  • 使用一个队列实现:
    • 每次要弹出“栈顶元素”(即队尾元素)时,都将队列中除最后一个元素的其他元素弹出并放到队尾,再将头一个元素弹出,即可实现栈

你可能感兴趣的:(leetcode,算法,职场和发展)