LeetCode——225. 用队列实现栈

使用队列实现栈的下列操作:

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

注意:

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

两个栈

这里就需要另外一个队列来辅助操作,我们总共需要两个队列,其中一个队列用来放最后加进来的数,模拟栈顶元素。剩下所有的数都按顺序放入另一个队列中。

当 push() 操作时,将新数字先加入模拟栈顶元素的队列中,如果此时队列中有数字,则将原本有的数字放入另一个队中,让新数字在这队中,用来模拟栈顶元素。

当 top() 操作时,如果模拟栈顶的队中有数字则直接返回,如果没有则到另一个队列中通过平移数字取出最后一个数字加入模拟栈顶的队列中。

当 pop() 操作时,先执行下 top() 操作,保证模拟栈顶的队列中有数字,然后再将该数字移除即可。当 empty() 操作时,当两个队列都为空时,栈为空。代码如下:

c++

class MyStack {
public:
    MyStack() {}
    void push(int x) {
        q2.push(x);
        while (q2.size() > 1) {
            q1.push(q2.front()); q2.pop();
        }
    }
    int pop() {
        int x = top(); q2.pop();
        return x;
    }
    int top() {
        if (q2.empty()) {
            for (int i = 0; i < (int)q1.size() - 1; ++i) {
                q1.push(q1.front()); q1.pop();
            }
            q2.push(q1.front()); q1.pop();
        }
        return q2.front();
    }
    bool empty() {
        return q1.empty() && q2.empty();
    }
private:
    queue<int> q1, q2;
}; 

一个栈

下面这种方法,比较好记,只要实现对了 push() 函数,后面三个直接调用队列的函数即可。

这种方法的原理就是每次把新加入的数插到前头,这样队列保存的顺序和栈的顺序是相反的,它们的取出方式也是反的,那么反反得正,就是我们需要的顺序了。

我们可以使用一个辅助队列,把q的元素也逆着顺序存入到辅助队列中,此时加入新元素x,再把辅助队列中的元素存回来,这样就是我们要的顺序了。

当然,我们也可以直接对队列q操作,在队尾加入了新元素x后,将x前面所有的元素都按顺序取出并加到队列到末尾,这样下次就能直接取出x了,符合栈到后入先出到特性,其他三个操作也就直接调用队列的操作即可,参见代码如下:

c++

class MyStack {
public:
    MyStack() {}
    void push(int x) {
        q.push(x);
        for (int i = 0; i < (int)q.size() - 1; ++i) {
            q.push(q.front()); q.pop();
        }
    }
    int pop() {
        int x = q.front(); q.pop();
        return x;
    }
    int top() {
        return q.front();
    }
    bool empty() {
        return q.empty();
    }
private:
    queue<int> q;
}; 

java

class MyStack {

    Queue<Integer> queue;
    
    public MyStack() {
        queue = new LinkedList<>();
    }
    
    public void push(int x) {
        queue.add(x);
        for(int i = 1; i < queue.size(); i++)
            queue.add(queue.remove());
    }
    
    public int pop() {
        return queue.poll();
    }
    
    public int top() {
        return queue.peek();
    }
    
    public boolean empty() {
        return queue.size() == 0;
    }
}

上面两种解法对于不同的输入效果不同,解法一花在 top() 函数上的时间多,所以适合于有大量 push() 操作,而 top() 和 pop() 比较少的输入。而第二种解法在 push() 上要花大量的时间,所以适合高频率的 top() 和 pop(),较少的 push()。两种方法各有千秋,互有利弊。

原文地址:https://www.cnblogs.com/wwj99/p/12388916.html