昨天笔试了两道题,在牛客网,看到核心代码考核的时候,我整个人都傻了……这是个什么模式。
找到了这个剑指offer,甚至发现了昨天笔试的原题,QWQ,唉注定过不了。
定个小目标,七天刷二十道左右,一天两道,应该不是很难,先从简单的开始。
第一个选定的时候栈模拟队列,不算难,主要是复习一下知识吧,毕竟好久没编了,手生。
(1)用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
有参考网上大佬的各类文章,其中:https://blog.csdn.net/cherrydreamsover/article/details/80466781
讲得最为清晰。
首先明白栈和队列的区别:
- 栈:先进后取,类似如一个桶,你只能拿你最后放入进去的东西。
- 队列:先进先出,类似于排队打饭,只有最前面人才能最先打饭后离开队伍。
如果,用两个栈模拟队列的思想就出来了。
设立两个栈(原题给出,核心代码好像都会规定好?)
stack<int> stack1;
stack<int> stack2;
其中,stack1作为数据插入的一个栈,而stcak2则是真正的容器。
也就是说,将数据从stack1存入,然后反向倒进stack2当中,这样虽然栈本身的性质没有改变,但是数据的排列顺序改变了,因此实现了队列的‘先进先出’。
举例子,比如一开始的输入数据是1,2,3,4。
stack1.push(node);
那么首先要把数据输入到stack1中存储为正常的:1,2,3,4;
然后使用stcak.top()将4,怼到stack2中,然后再将4进行删除操作。
再循环,将3怼到stack2中,再把三循环。
最后得到的两个栈。
stack1:
stack2:4,3,2,1
这样再提取出来就是1,2,3,4队列的顺序了。
if(stack2.empty())
{
while(!stack1.empty())
{
stack2.push(stack1.top());
stack1.pop();
}
}
在操作过程当中要注意stack2是否为空,否则就会乱套。
代码实现如下:
class Solution
{
public:
void push(int node) {
stack1.push(node);
}
int pop() {
if(stack2.empty())
{
while(!stack1.empty())
{
stack2.push(stack1.top());
stack1.pop();
}
}
int t = stack2.top();
stack2.pop();
return t;
}
private:
stack<int> stack1;
stack<int> stack2;
};
然后就是我所找到的那个博文提到的扩展知识。
如果何用两个队列伪装成栈。
这个想法也很巧妙,就是将除了最后一个元素的元素,全部挪到另外一个队列中,然后再将剩下的队列元素删除,将有元素的这个队列看做主队列,就完成了‘后进后出’的操作。
贴一下原文代码。
这个比栈多一个就是要两个队列来回倒腾。
template<typename T> class CStack
{
public:
CStack(void);
~CStack(void);
void appendTail(const T& node);
T deleteHead();
private:
queue<T> q1;
queue<T> q2;
};
template<typename T>
void CStack<T>::appendTail(const T& node)//实现栈元素的插入
{
//数据的插入原则:保持一个队列为空,一个队列不为空,往不为空的队列中插入元素
if (!q1.empty())
{
q1.push(node);
}
else
{
q2.push(node);
}
}
template<typename T>
T CStack<T>::deleteHead()//实现栈元素的删除
{
int ret = 0;
if (!q1.empty())
{
int num = q1.size();
while (num > 1)
{
q2.push(q1.front());
q1.pop();
--num;
}
ret = q1.front();
q1.pop();
}
else
{
int num = q2.size();
while (num > 1)
{
q1.push(q2.front());
q2.pop();
--num;
}
ret = q2.front();
q2.pop();
}
return ret;
}