232. 用栈实现队列(Implement Queue using Stacks)E

英文题目

  • Implement a first in first out (FIFO) queue using only two stacks. The implemented queue should support all the functions of a normal queue (push, peek, pop, and empty).

  • Implement the MyQueue class:

  • void push(int x) Pushes element x to the back of the queue.

  • int pop() Removes the element from the front of the queue and returns it.

  • int peek() Returns the element at the front of the queue.

  • boolean empty() Returns true if the queue is empty, false otherwise.

  • Notes:

  • You must use only standard operations of a stack, which means only push to top, peek/pop from top, size, and is empty operations are valid.

  • Depending on your language, the stack may not be supported natively. You may simulate a stack using a list or deque (double-ended queue) as long as you use only a stack's standard operations.

  • Follow-up: Can you implement the queue such that each operation is amortized O(1) time complexity? In other words, performing n operations will take overall O(n) time even if one of those operations may take longer.

  • Example 1:

  • Input
    ["MyQueue", "push", "push", "peek", "pop", "empty"]
    [[], [1], [2], [], [], []]
    Output
    [null, null, null, 1, 1, false]
    
    Explanation
    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
    
  • Constraints:

  • 1 <= x <= 9

  • At most 100 calls will be made to push, pop, peek, and empty.

  • All the calls to pop and peek are valid.

中文题目

  • 请你仅使用两个栈实现先入先出队列。队列应当支持一般队列的支持的所有操作(push、pop、peek、empty):

  • 实现 MyQueue 类:

  • void push(int x) 将元素 x 推到队列的末尾

  • int pop() 从队列的开头移除并返回元素

  • int peek() 返回队列开头的元素

  • boolean empty() 如果队列为空,返回 true ;否则,返回 false

  • 说明:

  • 你只能使用标准的栈操作 —— 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。

  • 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。

  • 进阶:

  • 你能否实现每个操作均摊时间复杂度为 O(1) 的队列?换句话说,执行 n 个操作的总时间复杂度为 O(n) ,即使其中一个操作可能花费较长时间。

  • 示例:

  • 输入:

  • 输入:
    ["MyQueue", "push", "push", "peek", "pop", "empty"]
    [[], [1], [2], [], [], []]
    输出:
    [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
    
  • 提示:

  • 1 <= x <= 9

  • 最多调用 100 次 push、pop、peek 和 empty

  • 假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)

双栈

  • 将一个栈 inStack 当作输入栈,用于 push 传入的数据,另一个栈当作输出栈,用于 pop 和 peek 操作。

  • 每次 pop 或 peek 时,若输出栈为空则将输入栈的全部数据依次弹出并压入输出栈

  • 时间复杂度:push 和 empty 为O(1),pop 和 peek 为均摊 O(1)。对于每个元素,至多入栈和出栈各两次,故均摊复杂度为O(1)

  • 空间复杂度:O(n),n 是操作总数。对于有 n 次 push 操作的情况,队列中会有 n 个元素,故空间复杂度为 O(n)

    # python3: 时间 44 ms, 击败 41.59%; 内存 15.85 MB, 击败 11.26%
    class MyQueue:
        def __init__(self):
            self.inStack = []
            self.outStack = []
    
        def push(self, x: int) -> None:
            self.inStack.append(x)
    
        def pop(self) -> int:
            if not self.outStack:
                while self.inStack:
                    self.outStack.append(self.inStack.pop())
    
            return self.outStack.pop()
    
        def peek(self) -> int:
            if not self.outStack:
                while self.inStack:
                    self.outStack.append(self.inStack.pop())
    
            return self.outStack[-1]
    
        def empty(self) -> bool:
            return not self.inStack and not self.outStack
    
    # Your MyQueue object will be instantiated and called as such:
    # obj = MyQueue()
    # obj.push(x)
    # param_2 = obj.pop()
    # param_3 = obj.peek()
    # param_4 = obj.empty()
    
    // c++: 时间 0 ms, 击败 100%; 内存 6.75 MB, 击败 9.00%
    class MyQueue {
    private:
        stack<int> inStack;
        stack<int> outStack;
    
    public:
        MyQueue() {}
        
        void push(int x) {
            inStack.push(x);
        }
        
        int pop() {
            if (outStack.empty()) {
                while (!inStack.empty()) {
                    outStack.push(inStack.top());
                    inStack.pop();
                }
            }
            int res = outStack.top();
            outStack.pop();
            return res;
        }
        
        int peek() {
            if (outStack.empty()) {
                while (!inStack.empty()) {
                    outStack.push(inStack.top());
                    inStack.pop();
                }
            }
            return outStack.top();
        }
        
        bool empty() {
            return inStack.empty() && outStack.empty();
        }
    };
    
    /**
     * Your MyQueue object will be instantiated and called as such:
     * MyQueue* obj = new MyQueue();
     * obj->push(x);
     * int param_2 = obj->pop();
     * int param_3 = obj->peek();
     * bool param_4 = obj->empty();
     */
    
    // java: 时间 0 ms, 击败 100%; 内存 38.09 MB, 击败 97.80%
    class MyQueue {
        Deque<Integer> inStack;
        Deque<Integer> outStack;
    
        public MyQueue() {
            inStack = new LinkedList<>();
            outStack = new LinkedList<>();
        }
        
        public void push(int x) {
            inStack.push(x);
        }
        
        public int pop() {
            if (outStack.isEmpty()) {
                while (!inStack.isEmpty()) {
                    outStack.push(inStack.peek());
                    inStack.pop();
                }
            }
            int res = outStack.peek();
            outStack.pop();
            return res;
        }
        
        public int peek() {
            if (outStack.isEmpty()) {
                while (!inStack.isEmpty()) {
                    outStack.push(inStack.peek());
                    inStack.pop();
                }
            }
            return outStack.peek();
        }
        
        public boolean empty() {
            return inStack.isEmpty() && outStack.isEmpty();
        }
    }
    
    /**
     * Your MyQueue object will be instantiated and called as such:
     * MyQueue obj = new MyQueue();
     * obj.push(x);
     * int param_2 = obj.pop();
     * int param_3 = obj.peek();
     * boolean param_4 = obj.empty();
     */
    
    // go: 时间 0 ms, 击败 100%; 内存 1.81 MB, 击败 29.91%
    type MyQueue struct {
        inStack []int
        outStack []int
    }
    
    func Constructor() MyQueue {
        return MyQueue{}
    }
    
    func (this *MyQueue) Push(x int)  {
        this.inStack = append(this.inStack, x)
    }
    
    func (this *MyQueue) Pop() int {
        if len(this.outStack) == 0 {
            for len(this.inStack) > 0 {
                this.outStack = append(this.outStack, this.inStack[len(this.inStack)-1])
                this.inStack = this.inStack[:len(this.inStack)-1]
            }
        }
        res := this.outStack[len(this.outStack)-1]
        this.outStack = this.outStack[:len(this.outStack)-1]
        return res
    }
    
    func (this *MyQueue) Peek() int {
        if len(this.outStack) == 0 {
            for len(this.inStack) > 0 {
                this.outStack = append(this.outStack, this.inStack[len(this.inStack)-1])
                this.inStack = this.inStack[:len(this.inStack)-1]
            }
        }
        return this.outStack[len(this.outStack)-1]
    }
    
    func (this *MyQueue) Empty() bool {
        return len(this.inStack) == 0 && len(this.outStack) == 0
    }
    
    /**
     * Your MyQueue object will be instantiated and called as such:
     * obj := Constructor();
     * obj.Push(x);
     * param_2 := obj.Pop();
     * param_3 := obj.Peek();
     * param_4 := obj.Empty();
     */
    
    // javascript: 时间 56 ms, 击败 84.77%; 内存 41.1 MB, 击败 15.13%
    var MyQueue = function() {
        this.inStack = [];
        this.outStack = [];
    };
    
    /** 
     * @param {number} x
     * @return {void}
     */
    MyQueue.prototype.push = function(x) {
        this.inStack.push(x);
    };
    
    /**
     * @return {number}
     */
    MyQueue.prototype.pop = function() {
        if (!this.outStack.length) {
            while (this.inStack.length) {
                this.outStack.push(this.inStack.pop());
            }
        }
        return this.outStack.pop();
    };
    
    /**
     * @return {number}
     */
    MyQueue.prototype.peek = function() {
        if (!this.outStack.length) {
            while (this.inStack.length) {
                this.outStack.push(this.inStack.pop());
            }
        }
    
        return this.outStack[this.outStack.length-1];
    };
    
    /**
     * @return {boolean}
     */
    MyQueue.prototype.empty = function() {
        return !this.inStack.length && !this.outStack.length;
    };
    
    /**
     * Your MyQueue object will be instantiated and called as such:
     * var obj = new MyQueue()
     * obj.push(x)
     * var param_2 = obj.pop()
     * var param_3 = obj.peek()
     * var param_4 = obj.empty()
     */
    
Last Updated:
Contributors: Shiqi Lu