1.用两个队列实现栈
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push
、top
、pop
和 empty
)。
实现 MyStack
类:
void push(int x)
将元素 x 压入栈顶。int pop()
移除并返回栈顶元素。int top()
返回栈顶元素。boolean empty()
如果栈是空的,返回true
;否则,返回false
。
注意:
- 你只能使用队列的基本操作 —— 也就是
push to back
、peek/pop from front
、size
和is empty
这些操作。 - 你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。
示例:
输入: ["MyStack", "push", "push", "top", "pop", "empty"] [[], [1], [2], [], [], []] 输出: [null, null, null, 2, 2, false] 解释: MyStack myStack = new MyStack(); myStack.push(1); myStack.push(2); myStack.top(); // 返回 2 myStack.pop(); // 返回 2 myStack.empty(); // 返回 False
提示:
1 <= x <= 9
- 最多调用
100
次push
、pop
、top
和empty
- 每次调用
pop
和top
都保证栈不为空
进阶:你能否仅用一个队列来实现栈。
题解:
定义两个队列,实现类为Linkedlist;
定义第一个队列暂时存储入栈的元素,用第二个队列实现栈的操作;
每次入栈时,先将元素入队到第一个队列,然后将第二个队列中的所有元素依次出队,再入第一个队列;这样就保证了栈后入先出的特点;
之后交换两个队列(使用一个中间队列进行交换),保证存储元素的队列每一次都为空
代码实现:
class MyStack {
Queue<Integer>queue;
Queue<Integer>queue1;
public MyStack() {
queue=new LinkedList<>();
queue1=new LinkedList<>();
}
// 入栈
public void push(int x) {
// 将元素添加到第二个队列
queue1.offer(x);
// 将第一个队列中的所有元素依次出队,并入队第二个队列,此时元素x就成为了第二个队列中最先入队的元素
while (!queue.isEmpty()){
queue1.offer(queue.poll());
}
// 将第一个队列与第二个队列进行交换,保证每一次进入第二个队列时都为空
Queue<Integer> queue2=queue;
queue=queue1;
queue1=queue2;
}
// 出栈
public int pop() {
return queue.poll();
}
// 获取栈顶元素
public int top() {
return queue.peek();
}
// 判断栈是否为空
public boolean empty() {
return queue.isEmpty();
}
}
2.用一个队列实现栈
题目描述与题1相同,只不过是用一个队列实现栈;
题解:
一个队列实现栈,注意添加第二个元素完成后,将第一个元素移出出来再添加,同理添加第三个元素完成后,将第一第二个个元素移出出来,再添加;这样就实现了栈先入后出的特性;
代码实现:
class MyStack {
Queue<Integer>queue;
public MyStack() {
queue=new LinkedList<>();
}
// 入栈
public void push(int x) {
int size=queue.size();
queue.offer(x);
for (int i = 0; i <size ; i++) {
queue.offer(queue.poll());
}
}
// 出栈
public int pop() {
return queue.poll();
}
// 获取栈顶元素
public int top() {
return queue.peek();
}
// 判断栈是否为空
public boolean empty() {
return queue.isEmpty();
}
}
3.用两个栈实现队列
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(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(双端队列)来模拟一个栈,只要是标准的栈操作即可。
示例 1:
输入: ["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
操作)
进阶:
- 你能否实现每个操作均摊时间复杂度为
O(1)
的队列?换句话说,执行n
个操作的总时间复杂度为O(n)
,即使其中一个操作可能花费较长时间。
题解:
定义两个栈,一个用作存储入队元素,另一个用作出队
在获取栈顶元素和出队时,如果出队的栈为空,则将存储入队元素的栈全部弹出,并入栈第二 个栈(注意必须一次性将存储的元素全部弹出,并入栈;即就是必须先判断出队栈是否为空, 再进行入栈操作)
代码实现:
class MyQueue {
// 用于存储入队元素
Stack<Integer> stack;
// 用于存储出队元素
Stack<Integer> stack1;
// 构造方法,初始化两个栈
public MyQueue() {
stack=new Stack<>();
stack1=new Stack<>();
}
// 向队列中添加元素
public void push(int x) {
stack.push(x);
}
public int pop() {
// 出队列时,如果出队栈为空,将入队栈全部出栈,依次进入出对栈
if(stack1.empty()){
while (!stack.empty()){
stack1.push(stack.pop());
}
}
return stack1.pop();
}
public int peek() {
// 获取栈顶元素时,如果出队栈为空,将入队栈全部出栈,依次进入出对栈
if(stack1.empty()){
while (!stack.empty()){
stack1.push(stack.pop());
}
}
return stack1.peek();
}
public boolean empty() {
if(stack.empty()&&stack1.empty()){
return true;
}
return false;
}
}