算法面试题:使用两个堆栈实现一个队列

55 篇文章 6 订阅

更详细的讲解和代码调试演示过程,请参看视频
如何进入google,算法面试技能全面提升指南

如果你对机器学习感兴趣,请参看一下链接:
机器学习:神经网络导论

队列的插入和删除遵循先入先出的原则,而堆栈元素的插入和删除遵循后进先出的原则。在很多应用场景下,我们需要使用堆栈来模拟队列,或者是使用队列来模拟堆栈。在数学上,已经能够严格证明,我们是不能使用含有n个元素的堆栈来模拟含有n个元素的队列的,这个证明非常复杂,详细证明可以参看论文: The Power of the queue.

用一个堆栈来模拟一个队列是不可能的,但是用两个堆栈来模拟一个队列确是可能的,问题是:如何使用两个堆栈来模拟一个队列,实现两种操作,enqueue 和 dequeue, enqueue是在队列末尾加入一个元素,dequeue是把队列的头部元素取出来。要求不能分配超过O(1)的内存,同时要求当进行m次enqueue或dequeue操作时,算法复杂度必须是O(m).

我们的做法是这样的,两个堆栈,假设分别为StackA, 和 StackB, 当使用enqueue将元素加入堆栈时,把该元素直接压入StackA, 如果需要使用dequeue将队列头元素出栈时,可以直接把StackB中的元素出栈。如果出栈时StackB中没有元素,那么把StackA中的元素逐个弹出然后压入StackB.

例如我们通过enqueue操作构造的一个队列如下:
1<- 2 <- 3 <- 4 <- 5

由于是enque操作,所以上面元素依次压入StackA.
StackA: StackB:
5
4
3
2
1

如果此时要dequeue获取队列的头元素1,那么我们把StackA中的元素逐个弹出,然后再压入B, 于是先弹出5,然后把5压入B, 依次进行后情况为:
StackA: StackB:
1
2
3
4
5
然后把B中的头元素弹出,于是数值1就可以获取了。

该算法不难,关键是如何证明该算法满足时间复杂度O(n).
每次执行enqueue操作是,我们只需要把元素通过push加入StackA,所以时间复杂度是O(1), 问题在于,如果执行dequue操作,我们有可能需要把元素从StackA 全部弹出,然后再压入StackB, 这个过程的时间复杂度是O(n)。事实上,任何一个元素,它能被操作的次数最多不过3次,一次是压入堆栈,一次是从StackA转移到StackB, 一次是从StackB中弹出,所以m次enqueue和dequue操作,其时间复杂度是3*m, 因此我们的算法时间复杂度是线性的。

用于我们算法中没有分配多余内存,因此空间复杂度是O(1).算法的实现代码如下:

import java.util.Stack;


public class StackQueue {
    private Stack<Integer> stackA = new Stack<Integer>();
    private Stack<Integer> stackB = new Stack<Integer>();

    public void enquene(int v) {
        stackA.push(v);
    }

    public int dequeue() {
        if (stackB.isEmpty()) {
            while (!stackA.isEmpty()) {
                stackB.push(stackA.pop());
            }
        }

        return stackB.pop();
    }
}

主入口处的代码为:

import java.util.ArrayList;
import java.util.Random;
import java.util.Stack;


public class StackAndQuque {
    public static void main(String[] args) {

        StackQueue sq = new StackQueue();
        System.out.println("enqueue: ");

        for (int i = 1; i <=5; i++) {
            sq.enquene(i);
            System.out.print(i + " ");
        }

        System.out.println("\ndequeue: ");
        for(int i = 0; i < 5; i++) {
            System.out.print(sq.dequeue() + " ");
        }

    }
}

代码执行后的结果为:

enqueue: 
1 2 3 4 5 
dequeue: 
1 2 3 4 5 

我们可以看到,元素的入队和出队遵守先入先出的次序,因此,我们代码的实现应该是正确的。

更多技术信息,包括操作系统,编译器,面试算法,机器学习,人工智能,请关照我的公众号:
这里写图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值