代码随想录算法训练营第10天|栈与队列一|232.用栈实现队列225.用队列实现栈
一、232.用栈实现队列
文档链接:代码随想录
题目链接:232.用栈实现队列
视频讲解:视频讲解
题目描述:
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(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:
def __init__(self):
self.stack_in = [] # 输入栈,用于push操作
self.stack_out = [] # 输出栈,用于pop和peek操作
def push(self, x: int) -> None:
self.stack_in.append(x) # 将元素x入栈
def pop(self) -> int:
if not self.stack_out: # 如果输出栈为空
while self.stack_in: # 将输入栈的元素一次弹出并压入到输出栈里
self.stack_out.append(self.stack_in.pop())
return self.stack_out.pop() # 弹出输出栈的栈顶元素
def peek(self) -> int:
if not self.stack_out: # 如果输出栈为空
while self.stack_in: # 将输入栈的元素一次弹出并压入到输出栈里
self.stack_out.append(self.stack_in.pop())
return self.stack_out[-1] # 返回栈顶元素,即为队列的开头元素
def empty(self) -> bool:
return not self.stack_in and not self.stack_out
# 如果输入栈和输出栈都为空,则队列为空,返回 True;否则,返回 False
# Your MyQueue object will be instantiated and called as such:
# obj = MyQueue()
# obj.push(x)
# param_2 = obj.pop()
# param_3 = obj.peek()
# param_4 = obj.empty()
二、225.用队列实现栈
文档链接:代码随想录
题目链接:225.用队列实现栈
视频讲解:视频讲解
题目描述:
请你仅使用两个队列实现一个后入先出(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
都保证栈不为空
**进阶:**你能否仅用一个队列来实现栈。
代码:
思路:使用双端队列(deque)来实现栈的基本操作。双端队列是一个可以从两端插入和删除的序列,因此它可以用来模拟栈的行为。
- 双队列
from collections import deque
class MyStack:
def __init__(self): # 初始化方法,当创建MyStack类的实例时会自动调用。
self.queue1 = deque() # 创建一个名为queue1的deque对象,用于模拟栈的底层数据结构。
self.queue2 = deque() # 创建一个名为queue2的deque对象,用于在pop操作时交换两个队列。
def push(self, x: int) -> None: # push方法,用于向栈顶添加一个整数x。
self.queue1.append(x) # 将x添加到queue1的右侧。
def pop(self) -> int: # pop方法,用于从栈顶删除一个整数并返回它。
if not self.queue2: # 如果输出栈为空
while len(self.queue1) > 1: # 遍历queue1的左侧元素(除了最后一个)。
self.queue2.append(self.queue1.popleft()) # 将每个元素从queue1左侧移除并添加到queue2的右侧。
# 交换两个队列的对象引用,使得原本的queue1现在指向被pop操作后的queue2,而原本的queue2现在指向原始的空队列。
self.queue1, self.queue2 = self.queue2, self.queue1
return self.queue2.popleft() # 返回被pop操作后的队列的第一个元素(即原来的栈顶元素)。
def top(self) -> int: # top方法,用于返回栈顶的整数,但不删除它。
return self.queue1[-1] # 返回queue1中的最后一个元素,即原来的栈顶元素。
def empty(self) -> bool: # empty方法,用于检查栈是否为空。
return not self.queue1 # 如果queue1为空,则返回True,否则返回False。
# Your MyStack object will be instantiated and called as such:
# obj = MyStack()
# obj.push(x)
# param_2 = obj.pop()
# param_3 = obj.top()
# param_4 = obj.empty()
- 单队列
from collections import deque
class MyStack:
# 初始化方法,当创建MyStack类的实例时会自动调用
def __init__(self):
# 创建一个名为queue的deque对象,用于模拟栈的底层数据结构
self.queue = deque()
# push方法,用于向栈顶添加一个整数x
def push(self, x: int) -> None:
# 将x添加到queue的右侧
self.queue.append(x)
# pop方法,用于从栈顶删除一个整数并返回它
def pop(self) -> int:
# 如果栈为空(即queue为空),则返回None
if self.empty():
return None
# 循环地将元素从queue的左侧移到右侧,直到只剩下一个元素。这样做的目的是为了保持deque的有序性,以便能够正确地返回栈顶元素。
for i in range(len(self.queue) - 1):
self.queue.append(self.queue.popleft())
# 返回从queue左侧弹出的元素(即原来的栈顶元素)
return self.queue.popleft()
# top方法,用于返回栈顶的整数,但不删除它
def top(self) -> int:
# 返回queue的最后一个元素,即栈顶元素。这里不需要进行任何检查,因为如果栈为空,pop和top方法会返回None。
return self.queue[-1]
# empty方法,用于检查栈是否为空
def empty(self) -> bool:
# 如果queue为空,则返回True,否则返回False。
return not self.queue
# Your MyStack object will be instantiated and called as such:
# obj = MyStack()
# obj.push(x)
# param_2 = obj.pop()
# param_3 = obj.top()
# param_4 = obj.empty()