题目:232.用栈实现队列、225. 用队列实现栈
参考链接:代码随想录
基础知识
cpp中的stack和queue,底层实现是deque即双向队列,不允许使用迭代器便利。栈和队列并不被归类为容器,而被视为容器适配器。
回顾基本操作:
栈:
s.push(x);
s.pop();//只出栈并不返回
s.top();
s.empty();
s.size();
队列:
q.push();
q.pop();//同样不返回
q.size();
q.empty();
q.front();
q.back();
232.用栈实现队列
思路:本题主要考察对栈和队列的理解程度。首先队列为先进先出,栈为先进后出,故我们使用两个栈s1和s2,s1用于输入,s2用于输出。当元素入队时,按顺序进入s1;当元素需要出队时,将s1中所有元素都出栈放入s2中,再将s2顶部元素出栈即可。弄明白了这个过程,代码就很容易写出。
class MyQueue {
public:
stack<int> s1,s2;//定义两个栈,一个进一个出
MyQueue() {
}
void push(int x) {
s1.push(x);
}
int pop() {
if(s2.empty()){//s2为空则把s1全部加入s2
while(!s1.empty()){
s2.push(s1.top());
s1.pop();
}
}
int ret=s2.top();
s2.pop();
return ret;
}
int peek() {
if(!s2.empty()){
return s2.top();
}
else{
while(!s1.empty()){
s2.push(s1.top());
s1.pop();
}
return s2.top();
}
}
bool empty() {
return (s1.empty() && s2.empty());
}
};
对比标答,我的peek()写复杂了,因为peek()需要返回队头元素即pop()出去的结果,可以直接调用pop(),然后再将其塞回去s2。主要是同样的代码避免了重复实现,这是个很重要的习惯。
标答:
int peek() {
int res = this->pop(); // 直接使用已有的pop函数
stOut.push(res); // 因为pop函数弹出了元素res,所以再添加回去
return res;
}
225. 用队列实现栈
思路:本题也不是很难。但是如果按照前一题一样的思想,一个用于in一个用于out,其实无法实现。
仔细想,如果1,2,3分别进入一个队列后,如果需要按照先进后出的原则出3,则需要将1和2都拿走,然后只剩下一个3,最后再将3出队。此时q1就是完全存放了栈中的元素,而q2仅仅是做了一个临时备份的作用,将1和2放入q2中,当pop()完成后,再将q2中元素放回q1即可。
class MyStack {
public:
queue<int> q1,q2;
MyStack() {
}
void push(int x) {
q1.push(x);
}
int pop() {
while(q1.size()>1){//q1多于1个元素
q2.push(q1.front());
q1.pop();
}
int ret=q1.front();
q1.pop();
while(!q2.empty()){//q2中元素放回q1
q1.push(q2.front());
q2.pop();
}
return ret;
}
int top() {
int ret=this->pop();//这次记得复用代码
q1.push(ret);
return ret;
}
bool empty() {
return q1.empty();//这里只要看q1
}
};
虽然成功运行,但和标答还有很大差距,首先是在pop()中,我每次while都判断q1.size(),导致时间复杂度变为O(n^2),实际上应该将size先记录,采用size–的方式,此时时间复杂度为O(n)。对于q2到q1也可以直接赋值,不用一个个push()。然后是top(),这里可以直接调用q1的**back()**函数,时间复杂度为O(1),我先调用了pop()导致时间复杂度为O(n)。
修改后:
int pop() {
int size = que1.size();
size--;
while (size--) { // 将que1 导入que2,但要留下最后一个元素
que2.push(que1.front());
que1.pop();
}
int result = que1.front(); // 留下的最后一个元素就是要返回的值
que1.pop();
que1 = que2; // 再将que2赋值给que1
while (!que2.empty()) { // 清空que2
que2.pop();
}
return result;
}
/** Get the top element. */
int top() {
return que1.back();
}
看解析还有只用一个queue的思路。其实就是每次pop()的时候将整个队列翻一圈,思路是一样的。
class MyStack {
public:
queue<int> q1;
MyStack() {
}
void push(int x) {
q1.push(x);
}
int pop() {
int size=q1.size();
while(size>1){//q1多于1个元素
q1.push(q1.front());
q1.pop();
size--;
}
int ret=q1.front();
q1.pop();
return ret;
}
int top() {
return q1.back();
}
bool empty() {
return q1.empty();//这里只要看q1
}
};