点击蓝色“五分钟学算法”关注我哟
加个“星标”,天天中午 12:15,一起学算法
作者 | 程序员小吴
来源 | 五分钟学算法
题目描述
使用栈实现队列的下列操作:
- push(x) — 将一个元素放入队列的尾部。
- pop() — 从队列首部移除元素。
- peek() — 返回队列首部的元素。
- empty() — 返回队列是否为空。
示例:
MyQueue queue = new MyQueue();
queue.push(1);
queue.push(2);
queue.peek(); // 返回 1
queue.pop(); // 返回 1
queue.empty(); // 返回 false
说明:
- 你只能使用标准的栈操作 — 也就是只有
push to top
,peek/pop from top
,size
和is empty
操作是合法的。 - 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
- 假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)。
题目分析
这是一道很典型的为初级算法爱好者准备的算法题,首先简单介绍一下 队列 和 栈 这两种数据结构。
队列
队列是一种 先进先出(first in – first out, FIFO)的数据结构,队列中的元素都从后端(rear)入队(push),从前端(front)出队(pop)。
栈
栈是一种 后进先出(last in – first out, LIFO)的数据结构,栈中元素从栈顶(top)压入(push),也从栈顶弹出(pop)。
为了满足队列的 FIFO 的特性,我们需要用到两个栈,用它们其中一个来进行入队操作,用另一个来进行出队操作。
动画演示
代码实现
//@author:程序员小吴
class MyQueue {
private Stack<Integer> in = new Stack<>(), out = new Stack<>();
//定义一个辅助函数来处理当 out 为空时,将 in 里面的数据挪到 out 中去
private void transferIfEmpty() {
if (out.empty()){
while (!in.empty()){
out.push(in.pop());
}
}
}
/** Initialize your data structure here. */
public MyQueue() {
}
/** Push element x to the back of queue. */
public void push(int x) {
in.push(x);
}
/** Removes the element from in front of queue and returns that element. */
public int pop() {
transferIfEmpty();
return out.pop();
}
/** Get the front element. */
public int peek() {
transferIfEmpty();
return out.peek();
}
/** Returns whether the queue is empty. */
public boolean empty() {
return in.empty() && out.empty();
}
}
复杂度分析
代码实现中涉及到多个函数,每个函数的复杂度是有所区别的。
push操作
- 时间复杂度:O(n) 。通过动画可知,除了新元素之外的其它元素,它们都会被压入两次,弹出两次。新元素只被压入一次,弹出一次。这个过程产生了 4n + 2 次操作,其中 n 是队列的大小。由于 压入 操作和 弹出 操作的时间复杂度为 O(1), 因此时间复杂度为 O(n)。
- 空间复杂度:O(n)。需要额外的内存来存储队列中的元素,因此空间复杂度为 O(n)。
pop操作
- 时间复杂度:O(1) 。
- 空间复杂度:O(1)。
peek操作
- 时间复杂度:O(1) 。
- 空间复杂度:O(1)。
empty操作
- 时间复杂度:O(1) 。
- 空间复杂度:O(1)。
知识点
栈、队列
1.【程序员】全球最厉害的 14 位程序员
2.【GitHub】我在 GitHub 上看到了一个丧心病狂的开源项目!
3.【算法】动画:七分钟理解什么是KMP算法
4.【数据结构】十大经典排序算法动画与解析,看我就够了!