队列实现栈的3种方法,全都击败了100%的用户!

作者 | 王磊

来源 | Java中文社群(ID:javacn666)

转载请联系授权(微信ID:GG_Stone)

本文已收录至 Github《小白学算法》系列:https://github.com/vipstone/algorith

之前我们讲过《用两个栈实现一个队列》,而今天我们要讲的是「用队列实现栈」,它们都属于常见的面试题,而我们今天要用多种方法来实现队列到栈的“转变”。

老规矩,先来回顾一下栈(Stack)和队列(Queue)的特性和常见方法。

栈是后进先出(LIFO)的数据结构,常见方法如下:

  • push():入栈方法,向栈顶添加元素;

  • pop():出栈方法,将栈顶的元素移除并返回元素;

  • peek():查询栈顶元素,并不会移除元素。

队列是先进先出(FIFO)的数据结构,常见方法如下:

  • offer():入队方法,向队尾添加元素;

  • poll():出队方法,从队头移除并返回元素;

  • peek():查询队头元素,并不会移除元素。

知道了这些基础内容之后,就来看今天的问题吧。

题目描述

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

push(x) -- 元素 x 入栈

pop() -- 移除栈顶元素

top() -- 获取栈顶元素

empty() -- 返回栈是否为空

注意:

  • 你只能使用队列的基本操作-- 也就是 push to back, peek/pop from front, size, 和 is empty 这些操作是合法的;

  • 你所使用的语言也许不支持队列。你可以使用 list 或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可;

  • 你可以假设所有操作都是有效的(例如, 对一个空的栈不会调用 pop 或者 top 操作)。

LeetCode 225:https://leetcode-cn.com/problems/implement-stack-using-queues/

题目解析

这道题的题目很好理解:只需要将先进先出的队列,转换为后进先出的“栈”就可以了,我们可以从多个方向入手来实现此功能,比如使用两个队列插入并交换的方式,或者是一个队列插入再交换的方式,或双端队列的方式来实现此功能,具体实现方法和代码如下。

实现方法 1:两个队列实现栈

之前我们用两个栈实现了一个队列的文章中,主要使用的是「负负得正」的思想,那么当看到此道题时,首先应该想到的是用两个队列来实现一个栈,但这里的实现思路和用栈实现队列的思路又略有不同,因为队列都是先进先出的,我们可以把它理解为「正数」,那么也就不能用「负负得正」的思想了,我们这里使用两个队列来实现栈,主要的操作思路是先将元素插入一个临时队列中,然后再将另一个队列的所有元素插入到临时队列的尾部,从而实现后进先出功能的,具体的实现步骤如下。

步骤一

添加首个元素,入列到临时队列 queue2

步骤二

因为正式队列中无元素,因此无需将 queue1 中的元素移动到临时队列 queue2 的尾部,直接将临时队列和正式队列互换即可:

步骤三

添加第二个元素,先入列到临时队列 queue2

步骤四

再将 queue1 中的元素移动到 queue2 的尾部,如下所示:


步骤五

再将 queue1queue2 进行互换:

步骤六

执行出队操作:

最终效果

从最终的效果图我们可以看出,通过两个队列已经实现了后进先出的特性,也就是完成了从队列到栈的转换,实现代码如下:

import java.util.Queue;class MyStack {Queue<Integer> queue1;Queue<Integer> queue2;public MyStack() {queue1 = new LinkedBlockingQueue();queue2 = new LinkedBlockingQueue();}/*** 入栈*/public void push(int x) {// 1.入列临时队列二queue2.offer(x);// 2.将队列一的所有元素移动到队列二while (!queue1.isEmpty()) {queue2.offer(queue1.poll());}// 3.队列一和队列二互换Queue<Integer> temp = queue1;queue1 = queue2;queue2 = temp;}/*** 出栈并返回此元素*/public int pop() {return queue1.poll();}/*** 查询栈顶元素*/public int top() {return queue1.peek();}/*** 判断是否为空*/public boolean empty() {return queue1.isEmpty();}
}

我们在 LeetCode 中提交以上测试代码,执行结果如下:

此方法很稳,竟然击败了 100% 的用户。

实现方法 2:一个队列实现栈

那我们可以不可以用一个队列来实现栈呢?答案是肯定的。

我们只需要执行以下两个步骤就可以实现将队列转换为栈了,具体实现步骤如下:

  1. 将元素入列到队尾;

  2. 再将除队尾之外的所有元素移除并重写入列。

这样操作之后,最后进入的队尾元素反而变成了队头元素,也就实现了后进先出的功能了,如下图所示。

步骤一

元素 1 入列:

步骤二

元素 2 入列:

步骤三

将最后一个元素之前的所有元素,也就是元素 1,出列重新入列:

步骤四

执行出队操作:

最终效果

以上思路的实现代码如下:

import java.util.Queue;class MyStack {Queue<Integer> queue1;public MyStack() {queue1 = new LinkedBlockingQueue();}/*** 入栈*/public void push(int x) {// 获取原队列长度(要移动的次数)int count = queue1.size();// 将元素放入队尾queue1.offer(x);// 将除最后一个元素外,其他的元素重新入队for (int i = 0; i < count; i++) {System.out.println("for");queue1.offer(queue1.poll());}}/*** 出栈并返回此元素*/public int pop() {return queue1.poll();}/*** 查询栈顶元素*/public int top() {return queue1.peek();}/*** 判断是否为空*/public boolean empty() {return queue1.isEmpty();}
}

我们把以上代码在 LeetCode 中提交,执行结果如下:


此方法依旧很稳,也是同样的击败了 100% 的用户,只不过此方法在内存方面有更好的表现。

实现方法 3:双端队列实现栈

如果觉得以上方法比较难的话,最后我们还有一个更简单的实现方法,我们可以使用 Java 中的双端队列 ArrayDeque 来实现将元素可以插入队头或队尾,同样移除也是,那么这样我们就可以从队尾入再从队尾出,从而就实现了栈的功能了。

双端队列结构如下:


我们来演示一下用双端队列实现栈的具体步骤。

步骤一

元素 1 入队:

步骤二

元素 2 入队(队尾):

步骤三

再从队尾出队:

最终效果

以上思路的实现代码如下:

import java.util.ArrayDeque;class MyStack {ArrayDeque<Integer> deque;public MyStack() {deque = new ArrayDeque<>();}/*** 入栈*/public void push(int x) {deque.offer(x);}/*** 出栈并返回此元素*/public int pop() {return deque.pollLast();}/*** 查询栈顶元素*/public int top() {return empty() ? -1 : deque.peekLast();}/*** 判断是否为空*/public boolean empty() {return deque.isEmpty();}
}

我们把以上代码在 LeetCode 中提交,执行结果如下:

总结

本文我们用 3 种方法实现了将队列转换为栈,其中最简单的方法是用 Java 中自带的双端队列 ArrayDeque 从队尾入并从队尾出就实现了栈 ,其他两个方法使用的是普通队列,通过入队之后再移动元素到入队元素之后的方法,从而实现了栈的功能。

小伙伴们,你学会了吗?


往期推荐

算法图解:如何用两个栈实现一个队列?


真不错,图解Java中的5大队列!


小白学算法:买卖股票的最佳时机!


关注我,每天陪你进步一点点!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/545277.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

where、having、group by、order by、count的使用注意

where、having、group by、order by、count的使用注意1_where、having、group by、order by的顺序2_group by的作用3_where和group by的组合4_group by和having的组合5_where、having、group by的组合使用6_count与group by的组合使用1_where、having、group by、order by的顺序…

很实用的21个SQL小技巧!

前言每一个好习惯都是一笔财富&#xff0c;本文基于MySQL&#xff0c;分SQL后悔药&#xff0c; SQL性能优化&#xff0c;SQL规范优雅三个方向&#xff0c;分享写SQL的21个好习惯&#xff0c;谢谢阅读&#xff0c;加油哈~1. 写完SQL先explain查看执行计划&#xff08;SQL性能优化…

阿里最喜欢问的多线程顺序打印的5种解法!

Keeper导读大家在换工作面试中&#xff0c;除了一些常规算法题&#xff0c;还会遇到各种需要手写的题目&#xff0c;所以打算总结出来&#xff0c;给大家个参考。全文 2929 字&#xff0c;剩下的是代码&#xff0c;P6 及以下阅读只需要 8 分钟&#xff0c;高 P 请直接关闭第一篇…

CSS入门

CSS入门1_CSS概要1.1_CSS引入方式2_CSS选择器3_字体样式3.1_字体属性3.2_字体类型&#xff1a;font-family3.3_字体大小&#xff1a;font-size3.4_字体粗细&#xff1a;font-weight3.5_字体颜色&#xff1a;color3.6_总结4_文本样式4.1_文本样式属性4.2_首行缩进&#xff1a;te…

23张图!万字详解「链表」,从小白到大佬!

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;链表和数组是数据类型中两个重要又常用的基础数据类型。数组是连续存储在内存中的数据结构&#xff0c;因此它的优势是可以通…

何为“秒传”

写在前面 最近一直在弄文件传输的组件&#xff0c;在讨论组里面&#xff0c;有同事提到“秒传”的功能。在目前的通信软件中也有网盘的功能&#xff0c;就从网上搜了一下&#xff0c;这里对“秒传”的实现思路做一下总结&#xff0c;在之后会写一个小的demo实现一下。没有其他&…

数组转List的3种方法和使用对比!

作者 | 大脑补丁来源 | blog.csdn.net/x541211190/article/details/79597236前言&#xff1a;本文介绍Java中数组转为List三种情况的优劣对比&#xff0c;以及应用场景的对比&#xff0c;以及程序员常犯的类型转换错误原因解析。一.最常见方式&#xff08;未必最佳&#xff09;…

oracle10g备份导入

2019独角兽企业重金招聘Python工程师标准>>> //导出 exp test/testgdsoft filed:\gd.dmp //删用户 drop user wkwx cascade; //用PLSQL创建数据数据库 create user hzjzjn identified by hzjzjn default tablespace BDP_DATABD; grant CREATE USER,DROP USER,ALTE…

VisualSVNServer的使用

VisualSVNServer的使用1_服务端初识1.1_创建新仓库1.2_创建用户并分配权限1_服务端初识 1.1_创建新仓库 右击Repository&#xff0c;点击create 点击下一步 输入仓库名 右击空白处&#xff0c;点击新建&#xff0c;点击project structure 输入工程名 1.2_创建用户并分…

安利一个IDEA骚操作:一键生成方法的序列图

在平时的学习/工作中&#xff0c;我们会经常面临如下场景&#xff1a;阅读别人的代码阅读框架源码阅读自己很久之前写的代码。千万不要觉得工作就是单纯写代码&#xff0c;实际工作中&#xff0c;你会发现你的大部分时间实际都花在了阅读和理解已有代码上。为了能够更快更清晰地…

c#中textbox属性_C#.Net中带有示例的TextBox.Multiline属性

c#中textbox属性Here we are demonstrating use of Multiline property of the TextBox Control. 在这里&#xff0c;我们演示了TextBox控件的Multiline属性的使用。 Multiline property contains two values: 多行属性包含两个值&#xff1a; True: We can enter text in mo…

MATLAB新手教程

MATLAB新手教程 1&#xff0e;MATLAB的基本知识 1-1、基本运算与函数 在MATLAB下进行基本数学运算&#xff0c;仅仅需将运算式直接打入提示号&#xff08;>>&#xff09;之後&#xff0c;并按入Enter键就可以。比如&#xff1a; >> (5*21.3-0.8)*10/25 an…

嗯,查询滑动窗口最大值的这4种方法不错....

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;本文已收录至 Github《小白学算法》系列&#xff1a;https://github.com/vipstone/algorithm这是一道比较基础的算法题&…

SVN客户端使用

SVN客户端使用1. 复制服务端URL2. 在客户端电脑新建文件夹用于存储版本代码3. 右击空白处&#xff0c;checkout4. 进入trunk目录&#xff0c;即可尝试新建文件并上传到服务端4.其他客户端更新版本5.解决代码冲突期间由于之前登陆过并设置为记住密码&#xff0c;所以整个过程并没…

25 张图,1.4 w字!彻底搞懂分布式事务原理

本文提纲如下&#xff1a;0. 前言1. 单数据源事务 & 多数据源事务2. 常见分布式事务解决方案2.1. 分布式事务模型2.2. 二将军问题和幂等性2.3. 两阶段提交&#xff08;2PC&#xff09; & 三阶段提交&#xff08;3PC&#xff09;方案2.4. TCC 方案2.5. 事务状态表方案2.…

des加密密码补位_密码学中的数据加密标准(DES)

des加密密码补位This is a Data Encryption Standard that is the asymmetric key generation for the encryption of digital data in cryptography. Therefore, its short key length of 56 bits of character criticized from the beginning or starting makes it too insec…

报告老板:这次的缓存事故是这样的...

事故背景公司最近安排了一波商品抢购活动&#xff0c;由于后台小哥操作失误最终导致活动效果差&#xff0c;被用户和代理商投诉了。老板让我带同事们一起复盘这次线上事故。什么原因造成的&#xff1f;抢购活动计划是零点准时开始&#xff0c;22&#xff1a;00 运营人员通过后台…

隐式转换

2019独角兽企业重金招聘Python工程师标准>>> 1&#xff1a;隐式转换应用 1.1 隐式转换为期望类型 隐式转换为期望类型是编译器会使用隐式操作的第一个地方。一旦编译器看到了X&#xff0c;但是需要Y&#xff0c;就会检查从X到Y的隐式转换函数。例如&#xff1a; val…

双“11”搞促销?用贪心算法来盘他!

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;这几年商家为了刺激消费是变着花样的推出各种各样的活动&#xff0c;以某多多为首的运营式电商更是让我们看到了营销的无限“…

AndroidStudio使用入门

AndroidStudio使用入门1_AndroidStudio activity的基本使用1.1_MainActivity和activity_main的初识1.2_Activity的清单文件简介1.3_几种重要文件的介绍1.4_基本布局的认识与使用1.4.1_RelativeLayout(相对布局)1.4.2_线性布局2_访问资源的方式2.1_java访问资源的方式2.2_xml访问…