面试手撕 (1):两个栈实现队列+两个队列实现栈

最近在找实习,打算开一个名叫‘面试手撕算法’的专栏,里面包含一些面试常见的算法题,而一般面试中的代码题会比笔试中的题简单一点,考的很基础的概念。但是往往有一些小细节被忽略,而使我们无法在短时间成功写出代码。

在这里,我会将我遇到的面试题和在一些帖子上常讨论的题进行整理,希望能帮助大家,一起学习。

昨天美团一面,面试官考了:用双栈实现一个队列,并且实现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; //返回出栈元素
	}
}

测试函数:

这个题比较基础,希望大家都掌握! 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值