最近在找实习,打算开一个名叫‘面试手撕算法’的专栏,里面包含一些面试常见的算法题,而一般面试中的代码题会比笔试中的题简单一点,考的很基础的概念。但是往往有一些小细节被忽略,而使我们无法在短时间成功写出代码。
在这里,我会将我遇到的面试题和在一些帖子上常讨论的题进行整理,希望能帮助大家,一起学习。
昨天美团一面,面试官考了:用双栈实现一个队列,并且实现push(),pop()方法。
两个栈实现一个队列
网上有一篇博客写的非常好,本文参考与它:两个队列实现一个栈 + 两个栈实现一个队列 Java
我们都知道:栈是先进后出,队列是先进先出的。我们现在有两个栈stack1,stack2。假如我们将a,b,c入栈stack1,此时我们需要出栈,对于队列来说,肯定要出的元素是第一个压入的a,但a在栈底,我们无法直接取出它。这是我们借助stack2,将stack1里的元素全部压入stack2元素,这时stack2里的元素就是a,b,c的逆序,a也就位于stack2的栈顶,到时pop()时就是对于stack2的pop()。那pop()完之后我们还用把stack2压回到stack1去吗?这里我们大可不必,因为就算压回去到时候在进行pop()还得把他再一次辗转到stack2里,这里我们不妨就让他继续留在stack2里。要pop()时我们直接对stack2进行pop,如果stack2为空,我们就把stack1里的元素全部压入stack2中,依次类推。
思想是这样:
我们将stack1作为添加的栈,将stack2作为删除的栈。
入队时,我们将其压入stack1。
出队时,我们先看stack2是否为空,如果为空则将stack1全部(一定注意是全部)压入stack2中,然后就可以对stack2进行pop()操作了。想想,如果这时我们发现将stack1全部压入stack2后stack2还是为空,则肯定就是说明我们所实现的这个队列已经为空了,没有元素无法出栈。
class TwoStackImplQueue{
//我们用stack1进行添加操作,stack2进行删除操作
Stack<Integer> stack1 = new Stack<>();
Stack<Integer> stack2 = new Stack<>();
public void push(Integer i) {
stack1.push(i);
}
public Integer pop() {
if(stack2.isEmpty()) {//如果stack2为空,则将stack1全部压入stack2中
while(!stack1.isEmpty()) {
stack2.push(stack1.pop());
}
}
if(stack2.isEmpty()) { //全部压入stack2后,发现stack2还是空的,则说明队列为空了
try {
throw new Exception("queue is Empty!");
} catch (Exception e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
return stack2.pop(); //对stack2进行pop()操作
}
}
两个队列实现一个栈
这个题是上面题的类似扩展,下面我们来看看。
我们假如将a,b,c入队列queue1,因为是栈,要pop()的话肯定是弹出最后一个元素c,但是c是在queue1的队列尾呀,这怎么办?相同的,我们可以将除了队尾的元素先全部放入queue2中,queue1就剩余最后一个队尾元素,这时我们将他弹出即可。类似,如果queue2中有元素,那么queue1肯定是空的,我们可以将queue2除了队尾元素全部压入queue1中,再弹出剩余那个队尾元素。这里我们可以看到,另一个空队列的作用就是:将那个不为空的队列队尾元素给调出来,就需要将队尾之前的元素先弄出来,而那个空队列就是容身之所。
加入元素也很简单,直接添加再不为空的那个队列尾部即可。
思路是这样:
添加元素:如果两个队列都为空的话,我们优先选择加入到queue1中。否则我们就加到不为空的那个队列中。
删除元素:将不为空的那个队列除队尾元素外全部压入另一为空的队列中,之后对剩余那个队尾元素出栈即可。
如果两个队列都为空,则说明实现的这个栈为空了。
class TwoQueueImplStack{
Queue<Integer> queue1 = new ArrayDeque<>();
Queue<Integer> queue2 = new ArrayDeque<>();
//入栈
public void add(Integer i) {
//两个队列都为空,选择优先加入queue1中
if(queue1.isEmpty() && queue2.isEmpty()) {
queue1.add(i);
return;
}
//queue2不空,加入元素到queue2中
if(!queue2.isEmpty()) {
queue2.add(i);
return;
}
//queue1不空,加入元素到queue1中
if(!queue1.isEmpty()) {
queue1.add(i);
return;
}
}
//出栈
public Integer poll() {
//两个队列都为空,则实现的栈就为空了
if(queue1.isEmpty() && queue2.isEmpty())
try {
throw new Exception("stack is Empty!");
} catch (Exception e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
//tail存储出栈的元素
Integer tail = null;
//queue1不空,将他除队尾元素外全部加入queue2中
if(!queue1.isEmpty()) {
while(queue1.size()>1) {
queue2.add(queue1.poll());
}
//对剩余那个队尾元素出栈即可
tail = queue1.poll();
}
//queue2不空,将他除队尾元素外全部加入queue1中
else if(!queue2.isEmpty()) {
while(queue2.size()>1) {
queue1.add(queue2.poll());
}
//对剩余那个队尾元素出栈即可
tail = queue2.poll();
}
return tail; //返回出栈元素
}
}
测试函数:
这个题比较基础,希望大家都掌握!