[LeetCode] 255.用队列实现栈

题目描述:使用队列实现栈的下列操作:

push(x) – 元素 x 入栈
pop() – 移除栈顶元素
top() – 获取栈顶元素
empty() – 返回栈是否为空

注意:

你只能使用队列的基本操作-- 也就是 push to back, peek/pop from front, size, 和 is empty 这些操作是合法的。
你所使用的语言也许不支持队列。 你可以使用 list 或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。
你可以假设所有操作都是有效的(例如, 对一个空的栈不会调用 pop 或者 top 操作)。

方法一 (两个队列,压入 -O(1), 弹出 -O(n))

思路:栈是一种 后进先出(last in - first out, LIFO)的数据结构,栈内元素从顶端压入(push),从顶端弹出(pop)。一般我们用数组或者链表来实现栈,但是这篇文章会来介绍如何用队列来实现栈。队列是一种与栈相反的 先进先出(first in - first out, FIFO)的数据结构,队列中元素只能从 后端(rear)入队(push),然后从 前端(front)端出队(pop)。为了满足栈的特性,我们需要维护两个队列 q1 和 q2。同时,我们用一个额外的变量来保存栈顶元素。

链接:https://leetcode-cn.com/problems/implement-stack-using-queues/solution/yong-dui-lie-shi-xian-zhan-by-leetcode/

方法二(两个队列, 压入 - O(n), 弹出 - O(1))

算法

1. 压入(push)

思路:让每一个新元素从 q2 入队,同时把这个元素作为栈顶元素保存。当 q1 非空(也就是栈非空),我们让 q1 中所有的元素全部出队,再将出队的元素从 q2 入队。通过这样的方式,新元素(栈中的栈顶元素)将会在 q2 的前端。我们通过将 q1, q2 互相交换的方式来避免把 q2 中的元素往 q1 中拷贝。

[LeetCode] 255.用队列实现栈_第1张图片
代码实现:

class MyStack {

    //两个队列模拟栈
    //队列q1  出队顺序=出栈顺序,队首元素=栈顶元素
    private Queue<Integer> q1 = new LinkedList<>();
    //队列q2  新元素先从队列q2中入队,该元素为最新栈顶元素,再进行出栈顺序调整
    //将队列q1中的元素依次出队,再入队列q2
    //最后将q1和q2队列交换,交换后,q1中元素出队顺序=出栈顺序
    private Queue<Integer> q2 = new LinkedList<>();
    private int top;

    /** Initialize your data structure here. */
    public MyStack() {
    }
    
    /** Push element x onto stack. */
    public void push(int x) {
        q2.add(x);
        top = x;
        while(!q1.isEmpty()){
            Integer temp = q1.remove();
            q2.add(temp);
        }
        //交换队列q1和q2,是的队列在没有push的时候,队列q2始终未空队列
        Queue<Integer> t = q1;
        q1 = q2;
        q2 = t;
    }
    
    /** Removes the element on top of the stack
    and returns that element. */
    public int pop() {
        int x = q1.remove();
        if(!q1.isEmpty()){
            top = q1.element();
        }
        return x;
    }
    
    /** Get the top element. */
    public int top() {
        return q1.element();
    }
    
    /** Returns whether the stack is empty. */
    public boolean empty() {
        return q1.isEmpty();
    }
}

/**
 * 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();
 * boolean param_4 = obj.empty();
 */

时间复杂度分析:

2. 弹出(pop)

直接让 q1 中元素出队,同时将出队后的 q1 中的队首元素作为栈顶元素保存。
复杂度分析

// Removes the element on top of the stack.
public void pop() {
    q1.remove();
    if (!q1.isEmpty()) {
    	top = q1.peek();
    }
}
  • 时间复杂度:O(1)
  • 空间复杂度:O(1)

3. 取栈顶元素(top)

栈顶元素被保存在 top 变量里,每次我们 压入 或者 弹出 一个元素的时候都会随之更新这个变量。

Java
// Get the top element.
public int top() {
return top;
}

  • 时间复杂度:O(1)
    栈顶元素每次都是被提前计算出来的,同时只有 top 操作可以得到它的值。
  • 空间复杂度:O(1)

方法三 (一个队列, 压入 - O(n), 弹出 - O(1))

上面介绍的两个方法都有一个缺点,它们都用到了两个队列。下面介绍的方法只需要使用一个队列。

算法

  1. 压入(push)

当我们将一个元素从队列入队的时候,根据队列的性质这个元素会存在队列的后端。

但当我们实现一个栈的时候,最后入队的元素应该在前端,而不是在后端。为了实现这个目的,每当入队一个新元素的时候,我们可以把队列的顺序反转过来

class MyStack {

    private LinkedList<Integer> q1 = new LinkedList<>();

    /** Initialize your data structure here. */
    public MyStack() {
    }
    
    /** Push element x onto stack. */
    public void push(int x) {
        //每当入队一个新元素的时候,我们可以把队列的顺序反转过来
        q1.add(x);
        int sz = q1.size();
        while (sz > 1) {
            q1.add(q1.remove());
            sz--;
        }
    }

    /** Removes the element on top of the stack
    and returns that element. */
    public int pop() {
        return q1.remove();
    }
    
    /** Get the top element. */
    public int top() {
        return q1.element();
    }
    
    /** Returns whether the stack is empty. */
    public boolean empty() {
        return q1.isEmpty();
    }
}

/**
 * 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();
 * boolean param_4 = obj.empty();
 */

你可能感兴趣的:(LeetCode)