题目描述
解法性能
我的思路
题意要求我们用栈实现队列。栈的特点是后进先出,队列的特点是先进先出——也就是说,我们需要用带有逆序特点的数据结构来实现顺序特点的数据结构,那我们只要两次逆序,不就变成正序了嘛。这提示我们用两个栈实现一个队列。
队列的主要功能是push和pop。如果我们把一个栈中元素出栈的顺序维护成队列的出队顺序,那实现起push和pop功能就比较直观了。这也比较好做,就是选一个栈(记做A)作为输出元素的栈,另一个栈(记做B)作为临时存储元素的栈。只要A中的元素出栈顺序与队列的元素出队顺序一致,那么队列的pop功能就实现了。如何让A中元素顺序与队列出队顺序保持一致呢——只要每次push一个元素的时候,我们把A中元素全都放入B中,在B的栈顶再push新加的元素,最后把B中元素放入A中就行了。
上面这个思路是可行的,可是问题在于,它的时间复杂度是O(n)的。有没有更快的做法呢?
我们发现,实际上没必要每次push/pop元素的时候,对之前push进来的元素都做一遍处理。我们可以换一个视角来理解队列:把队列的顶部当做pop操作的输出区,把队列除top位置外的其余位置视作这个输出区的缓冲区,如图1所示:
![](https://i-blog.csdnimg.cn/blog_migrate/6df9136147c616bbc75cb5e9d5c0a26d.png)
两个栈实现的队列则可看成:pop操作缓冲区的缓冲区-->pop操作的缓冲区-->pop操作的输出区,如图2所示:
![](https://i-blog.csdnimg.cn/blog_migrate/191d6b79870523c835a07510bdb3c0e1.png)
也就是说,两个栈的队列实现,相比原先的队列,多了一个缓冲区的存在。理想情况下,每个元素只需进出队列(缓冲区)一次,时间复杂度是O(2n);但是多的这个缓冲区让我们的元素需要进出两次,时间复杂度是O(4n)。这种情况下,pop/push的平均时间复杂度变成了O(1),比上一种做法要更高效。它的实现思路是:每次push元素的时候,放到缓冲区的缓冲区——栈A中;每次pop元素时,先从缓冲区——栈B中pop元素,如果栈B为空,则把栈A的元素放入栈B。
附上代码(第二种思路):
class MyQueue {
private:
stack <int> s_in, s_out;
public:
/** Initialize your data structure here. */
//MyQueue()
//{
// stack<int> s_in, s_out;
//}
/** Push element x to the back of queue. */
void push(int x) {
s_in.push(x);
}
/** Removes the element from in front of queue and returns that element. */
int pop() {
int res;
if (!s_out.empty())
{
;
}
else
{
int temp;
while (!s_in.empty())
{
temp = s_in.top();
s_in.pop();
s_out.push(temp);
}
}
res = s_out.top();
s_out.pop();
return res;
}
/** Get the front element. */
int peek()
{
int res;
if (!s_out.empty())
{
;
}
else
{
int temp;
while (!s_in.empty())
{
temp = s_in.top();
s_in.pop();
s_out.push(temp);
}
}
res = s_out.top();
return res;
}
/** Returns whether the queue is empty. */
bool empty() {
if (!s_in.empty() || !s_out.empty())
return false;
return true;
}
};