力扣日记:【栈与队列篇】用栈实现队列
日期:2023.
参考:代码随想录、力扣
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) ,即使其中一个操作可能花费较长时间。
题解
cpp ver
class MyQueue {
public:
// stack 的四种方法:pop(), push(), top(), empty()
stack<int> stIn;
stack<int> stOut;
MyQueue() { // 这是构造函数
}
void push(int x) {
stIn.push(x); // 推的话直接推到输入栈即可
}
int pop() {
// 如果输出栈为空,要先把所有元素都推到输出栈,再从输出栈导出(让输入栈底部的元素回到输出栈顶部)
if (stOut.empty()) {
while (!stIn.empty()) {
stOut.push(stIn.top()); // stack 的 pop() 不会返回元素?
stIn.pop();
}
}
// 如果输出栈不为空,则直接从输出栈弹出即可
int res = stOut.top();
stOut.pop(); // 先获取顶部值,再弹出(否则无法访问到)
return res;
}
int peek() {
// peek() 与 pop() 的操作类似,只是不需要导出
int res = this->pop(); // 先推出
stOut.push(res); // 再推回去(注意这里推回去要推回输出栈(因为是从输出栈推出的,而不能用this->push(),这是推到输入栈)
return res;
}
bool empty() {
if (stIn.empty() && stOut.empty()) { // 当输入栈和输出栈都为空,则为空
return true;
}
return false;
}
};
/**
* 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();
* bool param_4 = obj->empty();
*/
go ver
type MyQueue struct {
// go 中slice可用来作为栈(可方便地在末尾添加和删除元素)
stIn []int
stOut []int
}
func Constructor() MyQueue { // Constructor()为函数名,MyQueue 为返回值类型
// 在构造函数中初始化一个对象(其中对stIn和stOut申请内存空间)
return MyQueue{
stIn: make([]int, 0),
stOut: make([]int, 0),
}
}
func (this *MyQueue) Push(x int) {
this.stIn = append(this.stIn, x)
}
func (this *MyQueue) Pop() int {
if len(this.stOut) == 0 {
for len(this.stIn) > 0 {
this.stOut = append(this.stOut, this.stIn[len(this.stIn) - 1]) // 获取stIn最后一个元素并推入stOut
this.stIn = this.stIn[:len(this.stIn) - 1] // 删除最后一个元素
}
}
res := this.stOut[len(this.stOut) - 1]
this.stOut = this.stOut[:len(this.stOut) - 1]
return res
// 或
/*
inLen, outLen := len(this.stackIn), len(this.stackOut)
if outLen == 0 {
if inLen == 0 {
return -1
}
for i := inLen - 1; i >= 0; i-- {
this.stackOut = append(this.stackOut, this.stackIn[i]) // 每次仅改变访问的位置即可,最后再清空
}
this.stackIn = []int{} //导出后清空
outLen = len(this.stackOut) //更新长度值
}
val := this.stackOut[outLen-1]
this.stackOut = this.stackOut[:outLen-1]
return val
*/
}
func (this *MyQueue) Peek() int {
// 重用 pop()
res := this.Pop()
this.stOut = append(this.stOut, res)
return res
}
func (this *MyQueue) Empty() bool {
if len(this.stIn) == 0 && len(this.stOut) == 0 {
return true;
} else {
return false;
}
// return len(this.stackIn) == 0 && len(this.stackOut) == 0
}
/**
* Your MyQueue object will be instantiated and called as such:
* obj := Constructor();
* obj.Push(x);
* param_2 := obj.Pop();
* param_3 := obj.Peek();
* param_4 := obj.Empty();
*/
复杂度
时间复杂度: push和empty为O(1), pop和peek为O(n)
空间复杂度: O(n) // 要申请两个栈来存放
思路总结
- 栈在C++中的数据类型为
stack<type>。其常用方法如下- push():将元素压入栈
- pop():将栈顶部元素推出栈(但不会返回元素)
- top():访问栈顶部元素
- empty():判断栈是否为空
- 要用栈实现队列,需要用到两个栈,一个作为输入栈,一个作为输出栈,如代码随想录的示意图
- 其中,pop()操作需要借助输出栈:如果输出栈为空,要先把所有元素都推到输出栈,再从输出栈导出(让输入栈底部的元素回到输出栈顶部);如果输出栈不为空,则直接从输出栈弹出即可
- peek()与pop()类似,可重用pop()代码,在pop()获得顶部元素后再将其push()回去,但要注意这里推回去要推回输出栈(因为是从输出栈推出的,而不能用this->push(),这是推到输入栈)
文章介绍了如何使用两个栈实现一个支持push、pop、peek和empty操作的先入先出队列,包括C++和Go两种语言的具体实现和思路。
390

被折叠的 条评论
为什么被折叠?



