专栏首页五分钟学算法图解「剑指Offer」之使用栈实现队列

图解「剑指Offer」之使用栈实现队列

作者 | 程序员小吴

来源 | 五分钟学算法

题目描述

使用栈实现队列的下列操作:

  • push(x) -- 将一个元素放入队列的尾部。
  • pop() -- 从队列首部移除元素。
  • peek() -- 返回队列首部的元素。
  • empty() -- 返回队列是否为空。

示例:

MyQueue queue = new MyQueue();

queue.push(1);
queue.push(2);  
queue.peek();  // 返回 1
queue.pop();   // 返回 1
queue.empty(); // 返回 false

说明:

  • 你只能使用标准的栈操作 -- 也就是只有 push to toppeek/pop from topsizeis empty 操作是合法的。
  • 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
  • 假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)。

题目分析

这是一道很典型的为初级算法爱好者准备的算法题,首先简单介绍一下 队列 这两种数据结构。

队列

队列是一种 先进先出(first in - first out, FIFO)的数据结构,队列中的元素都从后端(rear)入队(push),从前端(front)出队(pop)。

栈是一种 后进先出(last in - first out, LIFO)的数据结构,栈中元素从栈顶(top)压入(push),也从栈顶弹出(pop)。


为了满足队列的 FIFO 的特性,我们需要用到两个栈,用它们其中一个来进行入队操作,用另一个来进行出队操作。

动画演示

代码实现

//@author:程序员小吴
class MyQueue {

    private Stack<Integer> in = new Stack<>(), out = new Stack<>();

    //定义一个辅助函数来处理当 out 为空时,将 in 里面的数据挪到 out 中去
    private void transferIfEmpty() {
         if (out.empty()){
             while (!in.empty()){
                   out.push(in.pop());
             }
         }
    }

    /** Initialize your data structure here. */
    public MyQueue() {

    }

    /** Push element x to the back of queue. */
    public void push(int x) {
        in.push(x);
    }

    /** Removes the element from in front of queue and returns that element. */
    public int pop() {
      transferIfEmpty();
      return out.pop();
    }

    /** Get the front element. */
    public int peek() {
      transferIfEmpty();
      return out.peek();
    }

    /** Returns whether the queue is empty. */
    public boolean empty() {
      return in.empty() && out.empty();
    }
}

复杂度分析

代码实现中涉及到多个函数,每个函数的复杂度是有所区别的。

push操作

  • 时间复杂度:O(n) 。通过动画可知,除了新元素之外的其它元素,它们都会被压入两次,弹出两次。新元素只被压入一次,弹出一次。这个过程产生了 4n + 2 次操作,其中 n 是队列的大小。由于 压入 操作和 弹出 操作的时间复杂度为 O(1), 因此时间复杂度为 O(n)。
  • 空间复杂度:O(n)。需要额外的内存来存储队列中的元素,因此空间复杂度为 O(n)。

pop操作

  • 时间复杂度:O(1) 。
  • 空间复杂度:O(1)。

peek操作

  • 时间复杂度:O(1) 。
  • 空间复杂度:O(1)。

empty操作

  • 时间复杂度:O(1) 。
  • 空间复杂度:O(1)。

知识点

栈、队列

本文分享自微信公众号 - 五分钟学算法(CXYxiaowu)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-09-03

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 快速了解TCP的流量控制与拥塞控制

    数据的传送过程中很可能出现接收方来不及接收的情况,这时就需要对发送方进行控制以免数据丢失。利用滑动窗口机制可以很方便地在TCP连接上对发送方的流量进行控制。TC...

    全菜工程师小辉
  • Java面向对象是人人都会的基础?来看看你掌握的怎么样

    关注公众号的朋友们都知道,楠哥最近出了一本书《Java零基础实战》,这本书中整合了我多年的一线研发经验,包括我对一些技术点的理解,可能与其他书籍讲解的角度略有不...

    南风
  • 详解Java多线程锁之synchronized

    synchronized是Java中解决并发问题的一种最常用的方法,也是最简单的一种方法。

    全菜工程师小辉
  • Redis的高级特性一览

    慢查询只记录Redis在处理存储的时间计数(图中的3步骤),并不包含网络通信时间和排队时间,所以客户端超时分析时要综合每个因素。

    全菜工程师小辉
  • Excel VBA解读(157): 数据结构—ArrayList(续)

    上篇文章,我们初步认识了ArrayList,下面进一步了解其排序、复制、数组转换等功能。

    fanjy
  • Swoole引擎原理的快速入门干货

    过去半年使用PHP和Java两种技术栈完成了一个游戏服务器项目。由于项目中有高频的网络请求,所以PHP技术栈尝试使用Swoole引擎(基于事件的高性能异步并行网...

    全菜工程师小辉
  • 动态规划快速入门

    动态规划算法一直是面试手撕算法中比较有挑战的一种类型。很多的分配问题或者调度问题实际上都可能用动态规划进行解决。(当然,如果问题的规模较大,有时候会抽象模型使用...

    全菜工程师小辉
  • 有关JIT你需要知道的

    JVM对代码执行的优化可分为运行时(runtime)优化和即时编译器(JIT)优化。 运行时优化主要是解释执行和动态编译通用的一些机制。比如说锁机制(如偏斜锁)...

    全菜工程师小辉
  • 深度学习笔记之《解析卷积神经网络》附下载地址

    实际上深度学习,只是机器学习的一个子领域,同样地,机器学习也是人工智能的一个子领域。但是随着深度学习的发展,尤其是在AlphaGo那场世纪大战之后,深度学习渐渐...

    Datawhale
  • GitHub万星资源:强化学习算法实现,教程代码样样全,还有详细学习规划

    自从有了强化学习(RL),AI上能星际争霸,下能雅达利称王,让内行人沉醉,让外行人惊奇。

    Datawhale

扫码关注云+社区

领取腾讯云代金券