面试题09:用两个栈实现队列

文章目录

  • 栈和队列的模拟实现
    • 用两个栈实现队列
      • 题目描述
      • 思路
      • 代码
    • 相关题目:用队列实现栈
      • 题目描述
      • 思路一:用两个队列
      • 思路二:只用一个队列

栈和队列的模拟实现

用两个栈实现队列

  • 232. Implement Queue using Stacks

题目描述

请用栈实现一个队列,支持如下四种操作:

  • push(x) —— 将元素x插到队尾;
  • pop() —— 将队首的元素弹出,并返回该元素;
  • peek() —— 返回队首元素;
  • empty() —— 返回队列是否为空;

注意:

你只能使用栈的标准操作:push to toppeek/pop from topsizeis empty
如果你选择的编程语言没有栈的标准库,你可以使用 list 或者 deque 等模拟栈的操作;
输入数据保证合法,例如,在队列为空时,不会进行 pop 或者 peek 等操作;

样例

MyQueue queue = new MyQueue();

queue.push(1);
queue.push(2);
queue.peek();  // returns 1
queue.pop();   // returns 1
queue.empty(); // returns false

思路

用两个栈来做,一个主栈,用来存储数据;一个辅助栈,用来当缓存。

  • push(x):我们直接将 x 插入主栈中即可。
  • pop():此时我们需要弹出最先进入栈的元素,也就是栈底元素。我们可以先将所有元素从主栈中弹出,压入辅助栈中。则辅助栈的栈顶元素就是我们要弹出的元素,将其弹出即可。然后再将辅助栈中的元素全部弹出,压入主栈中。
  • peek():可以用和 pop() 操作类似的方式,得到最先压入栈的元素。

empty():直接判断主栈是否为空即可。

时间复杂度分析

  • push() O ( 1 ) O(1) O(1)
  • pop(): 每次需要将主栈元素全部弹出,再压入,所以需要 O ( n ) O(n) O(n) 的时间;
  • peek():类似于 pop(),需要 O ( n ) O(n) O(n) 的时间;
  • empty() O ( 1 ) O(1) O(1)

代码

class MyQueue {
    Stack<Integer> stack1;
    Stack<Integer> stack2;

    /**
     * Initialize your data structure here.
     */
    public MyQueue() {
        stack1 = new Stack<>();
        stack2 = new Stack<>();
    }

    /**
     * Push element x to the back of queue.
     */
    public void push(int x) {
        stack1.push(x);
    }

    /**
     * Removes the element from in front of queue and returns that element.
     */
    public int pop() {
        if (stack2.isEmpty()) {
            while (!stack1.isEmpty()) {
                stack2.push(stack1.pop());
            }
        }
        return stack2.pop();
    }

    /**
     * Get the front element.
     */
    public int peek() {
        if (stack2.isEmpty()) {
            while (!stack1.isEmpty()) {
                stack2.push(stack1.pop());
            }
        }
        return stack2.peek();
    }

    /**
     * Returns whether the queue is empty.
     */
    public boolean empty() {
        return stack1.isEmpty() && stack2.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();
 */

相关题目:用队列实现栈

  • 225. Implement Stack using Queues

题目描述

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

push(x) – 元素 x 入栈

pop() – 移除栈顶元素

top() – 获取栈顶元素

empty() – 返回栈是否为空

注意:

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

思路一:用两个队列

维护两个队列 q1q2

push:当 q1 为空,则将新元素 x 添加到 q1 中,然后将 q2 中的元素出队,依次添加到 q1;当 q1 不为空,则将新元素 x 添加到 q2 中,然后将 q1 中的元素出队,依次添加到 q2

这样始终保持其中一个队列中当前的元素是按照后进先出的顺序存储

pop:不为空的队列中,队首元素出队

class MyStack {
    Queue<Integer> q1;
    Queue<Integer> q2;
    /** Initialize your data structure here. */
    public MyStack() {
        q1 = new LinkedList<>();
        q2 = new LinkedList<>();
    }
    
    /** Push element x onto stack. */
    public void push(int x) {
        if(q1.isEmpty()) {
            q1.add(x);
            for(int i = 0; i < q2.size(); i++)
                q1.add(q2.poll());
        }else {
            q2.add(x);
            for(int i = 0; i < q1.size(); i++)
                q2.add(q1.poll());
        }
    }
    
    /** Removes the element on top of the stack and returns that element. */
    public int pop() {
        return !q1.isEmpty() ? q1.poll() : q2.poll();
    }
    
    /** Get the top element. */
    public int top() {
        return q1.isEmpty() ? q2.peek() : q1.peek();
    }
    
    /** Returns whether the stack is empty. */
    public boolean empty() {
        return q1.isEmpty() && q2.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();
 */

时间复杂度

push O ( n ) O(n) O(n)

pop O ( 1 ) O(1) O(1)

思路二:只用一个队列

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

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

时间复杂度

push O ( n ) O(n) O(n)

pop O ( 1 ) O(1) O(1)

代码:

class MyStack {

    Queue<Integer> q;
    /** Initialize your data structure here. */
    public MyStack() {
        q = new LinkedList<Integer>();
    }
    
    /** Push element x onto stack. */
    public void push(int x) {
        q.add(x);
        for(int i = 1; i < q.size(); i ++) { 
            q.add(q.poll());
        }
    }
    
    /** Removes the element on top of the stack and returns that element. */
    public int pop() {
        return q.poll();
    }
    
    /** Get the top element. */
    public int top() {
        return q.peek();        
    }
    
    /** Returns whether the stack is empty. */
    public boolean empty() {
        return q.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();
 */

你可能感兴趣的:(面试题09:用两个栈实现队列)