day10 | LeetCode232.用栈实现队列、LeetCode225. 用队列实现栈
文章目录
一、LeetCode232.用栈实现队列:
方法:使用两个栈实现
1. 思路:
使用栈来模拟对了的行为,需要使用两个栈来实现,一个输入栈,一个输出栈。
执行语句:
queue.push(1);
- **输入栈:栈底|**1 栈口
- 输出栈:栈口 |栈底
queue.push(2);
- **输入栈:栈底|**1 ← 2 栈口
- 输出栈:栈口 |栈底
queue.pop();
- 输入栈:栈口 |栈底,
- 输出栈:栈口 1 → 2|栈底
pop()
输出 1,符合队列的先进先出规则。
push()
:只需要将数据放入输入栈即可。pop()
:如果输出栈为空,则需要将输入栈的数据全部导入输出栈,再从输出栈弹出数据。如果输出栈不为空,则直接弹出输出栈的数据即可。peek()
:pop()
和peek()
两个函数功能类似。empty()
:如果进栈和出栈都为空的话,说明模拟的队列为空了。
2. 代码实现:
class MyQueue {
Stack<Integer> stackIn;
Stack<Integer> stackOut;
public MyQueue() {
// 进栈
stackIn = new Stack<>();
// 出栈
stackOut = new Stack<>();
}
// 将元素 x 推到队列的末尾
public void push(int x) {
stackIn.push(x);
}
// 从队列的开头移除并返回元素
public int pop() {
if (stackOut.isEmpty()){
while (!stackIn.isEmpty()){
stackOut.push(stackIn.pop());
}
}
return stackOut.pop();
}
// 返回队列开头的元素
public int peek() {
int res = this.pop();
// 因为 pop 弹出了元素 res , 所有需要添加回去
stackOut.push(res);
return stackOut.peek();
}
// 如果队列为空, 返回 true ; 否则, 返回 false
public boolean empty() {
return stackIn.isEmpty() && stackOut.isEmpty();
}
}
3.复杂度分析:
入队 push()
- 时间复杂度:
O(1)
- 空间复杂度:
O(1)
出队 pop()
- 时间复杂度:
O(N)
- 空间复杂度:
O(N)
需要将输入栈的所有数据导入到输出栈,所有空间和时间复杂度为O(N)
返回队列开头的元素 peek()
- 时间复杂度:
O(N)
- 空间复杂度:
O(N)
是否为空 empty()
- 时间复杂度:
O(1)
- 空间复杂度:
O(1)
3.思考:
- 在工作如果遇到功能相近的函数一定要抽象出来,不要大量的复制粘贴,很容易出问题。
Reference
二、LeetCode225. 用队列实现栈:
方法1:使用两个队列实现
1. 思路:
使用两个队列来实现栈,que2
队列其实就是起到备份的作用。
push()
:正常加入数据即可。pop()
:将que1
队列除最后一个数据全部导入que2
队列,再把que1
队列里剩下的数据给弹出,就相当栈的后进先出。再把que2
的数据给导回给que1
。top()
:返回队列的尾部数据。empty()
:判断que1
队列是否为空。
2. 代码实现:
class MyStack {
// Deque 接口继承了 Queue 接口
// Queue 中的 add、poll、peek等效于 Deque 中的 addLast、pollFirst、peekFirst
Deque<Integer> queue1;
// 备份
Deque<Integer> queue2;
public MyStack() {
queue1 = new ArrayDeque<>();
queue2 = new ArrayDeque<>();
}
// 将元素 x 压入栈顶
public void push(int x) {
queue1.addLast(x);
}
// 移除并返回栈顶元素
public int pop() {
int size = queue1.size();
// 将 queue1 数据导入 queue2 ,最后一个数据除外
size--;
while (size-- > 0){
queue2.addLast(queue1.peekFirst());
queue1.pollFirst();
}
Integer res = queue1.pollFirst();
// 将 que2 对象的引用赋给了 que1
queue1 = queue2;
// 为 que2 分配一个新的空间
queue2 = new ArrayDeque<>();
return res;
}
// 返回栈顶元素
public int top() {
return queue1.getLast();
}
// 如果栈是空的,返回 true ;否则,返回 false
public boolean empty() {
return queue1.isEmpty();
}
}
3.复杂度分析:
入队 push()
- 时间复杂度:
O(1)
- 空间复杂度:
O(1)
出队 pop()
- 时间复杂度:
O(N)
- 空间复杂度:
O(N)
返回队列开头的元素 peek()
- 时间复杂度:
O(1)
- 空间复杂度:
O(1)
判断是否为空 empty()
- 时间复杂度:
O(1)
- 空间复杂度:
O(1)
方法2:使用一个队列实现栈
1. 思路:
一个队列在模拟栈弹出元素的时候只要将队列头部的元素(除了最后一个元素外) 重新添加到队列尾部,此时在去弹出元素就是栈的顺序了。
2. 代码实现:
class MyStack {
// Deque 接口继承了 Queue 接口
// Queue 中的 add、poll、peek等效于 Deque 中的 addLast、pollFirst、peekFirst
Deque<Integer> queue1;
public MyStack() {
queue1 = new ArrayDeque<>();
}
// 将元素 x 压入栈顶
public void push(int x) {
queue1.addLast(x);
}
// 移除并返回栈顶元素
public int pop() {
int size = queue1.size();
// 除了最后一个元素外, 重新添加到队列尾部
size--;
while (size-- > 0){
queue1.addLast(queue1.peekFirst());
queue1.pollFirst();
}
Integer res = queue1.pollFirst();
return res;
}
// 返回栈顶元素
public int top() {
return queue1.getLast();
}
// 如果栈是空的,返回 true ;否则,返回 false
public boolean empty() {
return queue1.isEmpty();
}
}
3.复杂度分析:
入队 push()
- 时间复杂度:
O(1)
- 空间复杂度:
O(1)
出队 pop()
- 时间复杂度:
O(N)
- 空间复杂度:
O(N)
返回队列开头的元素 peek()
- 时间复杂度:
O(1)
- 空间复杂度:
O(1)
判断是否为空 empty()
- 时间复杂度:
O(1)
- 空间复杂度:
O(1)