资讯动态

栈与队列基础:应用场景与经典面试题

发布时间:2026/8/17 11:28:14 来源:尧图企业网站定制
文章目录前言一、先把栈给你扒得明明白白连食堂阿姨都能懂1.1 到底什么是栈别背定义看生活例子就懂了1.2 栈的核心操作就这4个多一个都没有1.3 栈的两种实现方式数组vs链表面试常问的坑都在这二、队列别和栈搞混了这俩是双胞胎但性格完全相反2.1 什么是队列还是看生活例子一秒就懂2.2 队列的核心操作同样4个和栈对应着记2.3 队列的4种常见类型面试必考的全在这2.3.1 循环队列解决普通队列的假溢出问题2.3.2 双端队列Deque栈和队列的结合体全能选手2.3.3 优先队列VIP专属通道谁优先级高谁先上三、别觉得这俩货没用2026年了从CRUD到AI大模型到处都是它们的身影3.1 栈的核心应用场景从操作系统底层到AI大模型全是它3.1.1 函数调用栈操作系统的底层基石没有它程序根本跑不起来3.1.2 括号匹配IDE语法校验的核心逻辑你天天都在用3.1.3 AI领域专属应用大模型思维链CoT的底层逻辑3.2 队列的核心应用场景从秒杀系统到大模型服务全靠它扛着3.2.1 任务调度与流量削峰后端开发的万金油大模型服务的核心3.2.2 广度优先搜索BFS算法的核心自动驾驶路径规划全靠它3.2.3 大模型解码核心beam search束搜索底层就是优先队列四、面试被问栈和队列直接慌2026年最高频的5道经典面试题手把手给你讲明白4.1 面试题1用两个栈实现队列剑指Offer原题10个公司面试9个考4.2 面试题2用两个队列实现栈和上面的题成对出现面试必问4.3 面试题3有效的括号LeetCode第20题入门必刷面试100%会考4.4 面试题4滑动窗口最大值LeetCode第239题中大厂必考题字节腾讯最爱考4.5 面试题5TOP K问题海量数据找前K大的数互联网公司必问AI领域高频五、最后说几句掏心窝子的话P.S. 目前国内还是很缺AI人才的希望更多人能真正加入到AI行业共同促进行业进步增强我国的AI竞争力。想要系统学习AI知识的朋友可以看看我精心打磨的教程 http://blog.csdn.net/jiangjunshow教程通俗易懂高中生都能看懂还有各种段子风趣幽默从深度学习基础原理到各领域实战应用都有讲解我22年的AI积累全在里面了。注意教程仅限真正想入门AI的朋友否则看看零散的博文就够了。前言兄弟们先问个扎心的问题你是不是刷了几百道LeetCode背了无数遍数据结构八股文面试的时候面试官一句“栈和队列有啥区别分别在大模型推理里有啥应用”你瞬间就懵了张口就来“栈是后进先出队列是先进先出”结果面试官再追问一句“为啥函数调用用栈不用队列大模型的beam search解码为啥用优先队列”你当场就哑火恨不得找个地缝钻进去还有更扎心的2026年了很多人张口闭口就是大模型、智能体、AIGC觉得自己走在技术前沿结果写个括号匹配的校验逻辑硬是写了几十行if-else嵌套最后还一堆bug做个大模型API的流量削峰连个队列都用不明白上线就被用户的请求打崩系统甚至写个递归的神经网络前向传播代码动不动就栈溢出还不知道问题出在哪。我在AI行业摸爬滚打了22年面过的候选人没有一千也有八百最近这两年尤其是2026年这种情况见得太多了。太多人一心追着风口跑觉得学个大模型调包、搞个智能体框架就能薪资翻倍却把栈和队列这种最基础、最核心的数据结构丢到了九霄云外。但现实就是不管是传统CRUD开发还是现在最火的AI大模型、自动驾驶、智能体开发底层逻辑全是这些基础数据结构撑起来的。你去看2026年国内所有大厂的校招、社招面试不管是后端岗还是AI算法岗栈和队列永远是绕不开的必考点不是面试官喜欢考八股而是这东西真的是你写代码的基本功基本功不牢别的全是空中楼阁。很多人说栈和队列太简单了不就是两个存取数据的容器吗但我敢说80%的程序员都没真正把这两个货搞明白。这篇文章我就用最通俗的段子、最接地气的类比把栈和队列给你扒得明明白白从底层原理到2026年最新的应用场景再到面试最高频的经典题全给你讲透高中生都能看懂。一、先把栈给你扒得明明白白连食堂阿姨都能懂1.1 到底什么是栈别背定义看生活例子就懂了很多教材一上来就给你甩“栈是一种限定仅在表尾进行插入和删除操作的线性表遵循后进先出LIFO原则”看完你更懵了。其实栈这东西你天天都在接触只是你没发现而已。打个最通俗的比方你去公司食堂打饭后厨的阿姨把洗干净的盘子一个一个叠起来放好第一个洗好的盘子在最底下最后一个洗好的盘子在最上面。阿姨打饭的时候只能从最上面拿盘子最后放上去的盘子第一个被拿走最先放上去的盘子最后才会被拿走。这就是栈还有很多例子你玩玩具枪的弹夹装子弹的时候一颗一颗压进去第一颗压进去的在弹夹最底下最后一颗压进去的在最上面开枪的时候先打出去的是最后压进去的那颗子弹你叠衣服最后叠好的衣服放在最上面早上穿衣服先拿的是最上面的那件甚至你吃薯片最后装进去的薯片在最上面你先吃的也是最上面的。说白了栈的核心规矩就一条后进先出Last In First Out简称LIFO最后进来的第一个出去就这么简单。1.2 栈的核心操作就这4个多一个都没有很多教材把栈的操作讲得花里胡哨其实栈的核心操作就4个你把这4个搞懂栈的操作就全明白了我还是用食堂叠盘子的例子给你讲入栈push就是把洗好的盘子放到盘子堆的最上面对应就是把数据放到栈的顶端。出栈pop就是把盘子堆最上面的那个盘子拿走对应就是把栈顶端的数据取出来同时把这个数据从栈里删掉。取栈顶peek就是低头看看盘子堆最上面的盘子是啥样的不拿走对应就是看看栈顶端的数据是啥不删除这个数据。判空isEmpty就是看看盘子堆里还有没有盘子对应就是判断栈里还有没有数据。就这4个操作没有别的花活栈所有的功能都是基于这4个操作实现的。很多人用Python写代码直接用list就实现了栈append()方法就是入栈pushpop()方法不带参数就是出栈poplist[-1]就是取栈顶peeklen(list)0就是判空isEmpty几行代码就搞定非常方便。1.3 栈的两种实现方式数组vs链表面试常问的坑都在这栈的实现本质上就两种一种是基于数组实现的顺序栈一种是基于链表实现的链式栈我给你讲明白各自的优缺点还有面试会追问的坑。首先是顺序栈数组实现这个是最常用的就像我们用Python的list实现栈一样底层是一块连续的内存空间用一个指针下标标记栈顶的位置。优点实现简单存取数据的速度快因为是连续的内存空间CPU缓存命中率高。缺点数组的大小是固定的静态数组会有栈溢出的问题就算是动态数组频繁扩容的时候需要重新申请内存还要把原来的数据复制过去有性能开销。然后是链式栈链表实现用单链表就能实现每个节点存数据和下一个节点的指针栈顶就放在链表的头节点位置入栈就是在头节点前面加一个新节点出栈就是删掉头节点。优点没有固定的大小限制用多少内存就申请多少不会有栈溢出的问题只要内存够就能一直入栈。缺点每个节点都要存指针内存开销大而且节点的内存是不连续的CPU缓存命中率低存取速度比顺序栈慢。这里给兄弟们提个面试常问的坑2026年了很多人用Python的list当栈用但是很少有人知道list的底层是动态数组当你频繁push大量数据的时候list会自动扩容每次扩容都会申请一块更大的内存把原来的数据复制过去这个过程是有性能开销的。如果你提前知道要存多少数据最好提前给list初始化好大小避免频繁扩容这个细节你面试的时候说出来面试官直接对你刮目相看。二、队列别和栈搞混了这俩是双胞胎但性格完全相反很多人学完栈再学队列直接就搞混了觉得这俩不都是线性表吗其实它俩就像一对双胞胎长得像但性格完全相反栈是“后进先出”队列是“先进先出”完全反过来了。2.1 什么是队列还是看生活例子一秒就懂同样别背教材里的定义还是看你天天接触的例子你去食堂打饭要排队第一个来排队的人站在队伍最前面第一个打到饭打完就走后面来的人只能站在队伍的最后面排队前面的人打完饭才能轮到你。先排队的先吃饭后排队的后吃饭绝对不会出现后面的人插到前面先打饭的情况就算阿姨的手再抖也不会坏了这个规矩。这就是队列还有很多例子高速收费站的排队车辆先到的先过收费站后到的后过你去医院门诊排队看病先挂号的先看医生后挂号的后看甚至你给客服打电话排队等待接入先打进来的电话先被客服接入。说白了队列的核心规矩也只有一条先进先出First In First Out简称FIFO最先进来的第一个出去就这么简单。2.2 队列的核心操作同样4个和栈对应着记队列的核心操作也是4个和栈的操作对应着记非常好记还是用排队打饭的例子给你讲入队enqueue就是新来的人站到队伍的最后面排队对应就是把数据放到队列的尾部。出队dequeue就是队伍最前面的人打完饭走了对应就是把队列头部的数据取出来同时把这个数据从队列里删掉。取队头peek就是看看队伍最前面的人是谁不叫他走对应就是看看队列头部的数据是啥不删除这个数据。判空isEmpty就是看看队伍里还有没有人对应就是判断队列里还有没有数据。就这4个操作队列所有的功能都是基于这4个操作实现的是不是非常简单2.3 队列的4种常见类型面试必考的全在这普通的队列很好理解但是面试的时候很少只考普通队列更多的是考循环队列、双端队列、优先队列这些也是2026年AI开发、后端开发里用的最多的我一个个给你讲明白。2.3.1 循环队列解决普通队列的假溢出问题先给兄弟们讲个普通队列的坑如果你用数组实现普通队列用两个指针分别标记队头和队尾入队的时候队尾指针往后移出队的时候队头指针往后移时间长了队头指针前面会有很多空的内存空间但是队尾指针已经到了数组的最后面没法再入队了这就是假溢出——数组里明明有空位置却没法入队了。怎么解决这个问题循环队列就来了。通俗来讲循环队列就是把数组的首尾连起来变成一个环形的结构队尾指针到了数组最后面的时候直接绕回到数组的开头用前面空出来的位置完美解决了假溢出的问题还能重复利用数组的内存空间不会浪费。循环队列是面试超高频的考点尤其是手写实现后面的面试题里我会给你详细讲。2.3.2 双端队列Deque栈和队列的结合体全能选手双端队列顾名思义就是队列的两端都可以入队和出队队头可以入队也可以出队队尾也可以入队也可以出队。这就厉害了相当于把栈和队列的功能合二为一了如果你只允许队尾入队、队尾出队它就是一个栈如果你只允许队尾入队、队头出队它就是一个普通队列。双端队列在实际开发里用的非常多比如后面要讲的滑动窗口最大值问题就是用双端队列实现的Python里的collections.deque就是现成的双端队列性能非常高入队出队的时间复杂度都是O(1)。2.3.3 优先队列VIP专属通道谁优先级高谁先上优先队列就打破了普通队列“先进先出”的规矩它不管你什么时候入队的只看你的优先级优先级最高的永远第一个出队。还是用生活例子讲你去医院排队看病普通病人按挂号顺序排队但是突然来了一个危重的急诊病人他的优先级最高不管他什么时候来的医生都会先给他看病这就是优先队列。优先队列在2026年的技术开发里用的简直太多了大模型API的请求调度VIP用户的请求优先级更高先处理自动驾驶的任务调度避障的任务优先级最高先执行还有大模型生成文本的时候beam search束搜索找前K个概率最高的token底层就是优先队列实现的。优先队列的底层一般是用堆来实现的小顶堆和大顶堆后面的TOP K面试题里我会给你详细讲。三、别觉得这俩货没用2026年了从CRUD到AI大模型到处都是它们的身影很多兄弟说我学这个有啥用我写CRUD又用不到搞大模型也不用自己写栈和队列。那你就大错特错了我可以这么说你每天用的软件、写的代码、调用的大模型API底层全是栈和队列在撑着只是你没发现而已。3.1 栈的核心应用场景从操作系统底层到AI大模型全是它3.1.1 函数调用栈操作系统的底层基石没有它程序根本跑不起来这个是栈最核心、最底层的应用你写的任何代码只要有函数调用底层就一定用了栈。给兄弟们通俗讲一下比如你写了一段代码主函数里调用了A函数A函数里调用了B函数B函数里调用了C函数。程序执行的时候会先把主函数的上下文压入栈里然后调用A函数把A函数的上下文压入栈里再调用B函数把B函数的上下文压入栈里再调用C函数把C函数的上下文压入栈里。执行的时候先执行C函数C函数执行完了把C函数的上下文从栈顶弹出来回到B函数继续执行B函数执行完了把B函数的上下文从栈顶弹出来回到A函数继续执行A函数执行完了把A函数的上下文从栈顶弹出来回到主函数继续执行。完美符合栈的“后进先出”原则后调用的函数先执行完先出栈。这里面试常问一个问题为啥函数调用必须用栈不能用队列答案很简单因为函数调用的嵌套逻辑就是后调用的必须先执行完队列是先进先出用队列的话你得先执行完最先调用的主函数才能执行后面的A、B、C函数那嵌套调用直接就废了程序根本没法跑。还有很多AI新手常踩的坑写递归代码的时候动不动就栈溢出为啥因为每一次递归调用都会把函数的上下文压入栈里而栈的大小是有限的递归层数太深栈里装不下了就会溢出。比如你写一个深度神经网络的前向传播用递归实现层数太多直接就栈溢出了很多人遇到这个问题还不知道为啥其实就是栈的基础没搞明白。3.1.2 括号匹配IDE语法校验的核心逻辑你天天都在用你写代码的时候少写了一个括号IDE立马就给你标红报错这个功能的底层逻辑就是用栈实现的。比如你写的代码里有这样一段if (a 0) { for (int i0; i10; i) { System.out.println(i); } }这么多括号怎么判断是不是全匹配用栈逻辑非常简单遍历字符串遇到左括号(、{、[就直接入栈遇到右括号)、}、]先看栈是不是空的如果是空的说明这个右括号没有对应的左括号直接报错如果栈不是空的就取出栈顶的左括号看是不是和当前的右括号匹配匹配就出栈不匹配直接报错遍历完整个字符串之后看栈是不是空的如果是空的说明所有的括号都匹配成功了如果不是空的说明有左括号没有对应的右括号还是报错。就这么简单的逻辑几行代码就搞定了比你写几十行if-else靠谱多了。2026年了所有的代码编辑器、代码大模型的语法校验模块底层还是用这个逻辑从来没变过。3.1.3 AI领域专属应用大模型思维链CoT的底层逻辑2026年了大家用大模型的时候都知道让模型“一步步思考”用思维链CoT能大幅提升模型的推理准确率但是很多人不知道思维链的底层逻辑就是栈的思想。给兄弟们通俗讲一下大模型做复杂推理的时候会把一个大问题拆解成多个子问题比如要算“1020*(30-10)”模型会先拆解成先算括号里的30-1020再算20*20400再算10400410。这个过程就是把大问题压入栈里然后拆解成子问题把子问题压入栈里先解决最栈顶的子问题解决完了出栈再解决上一层的问题直到把最底层的大问题解决完美的后进先出逻辑。还有大模型的上下文窗口管理、RAG检索的递归式文档解析底层全是栈的逻辑你把栈搞懂了再去看大模型的推理逻辑就会豁然开朗。3.2 队列的核心应用场景从秒杀系统到大模型服务全靠它扛着3.2.1 任务调度与流量削峰后端开发的万金油大模型服务的核心队列最常用的场景就是异步任务调度和流量削峰这个不管是传统后端还是AI大模型服务都离不开。先讲传统后端比如用户在你的网站上注册你需要给用户发激活邮件、发短信通知这些操作不需要同步执行如果你同步等邮件发完再给用户返回结果用户可能要等好几秒体验非常差。这时候你就可以把发邮件、发短信的任务放到队列里直接给用户返回注册成功然后有专门的消费者从队列里取出任务异步执行用户体验直接拉满。还有秒杀系统比如618大促一秒钟有几十万用户请求进来你的系统根本扛不住这时候就可以用队列做流量削峰把所有用户的请求先放到队列里系统按自己能承受的速度从队列里取出请求一个个处理多余的请求直接排队等待避免系统被打崩这就是队列最经典的用法。2026年了所有的大模型API服务底层都是用队列做流量调度的。大家都知道大模型的推理非常吃GPU算力一块GPU一秒钟只能处理几十个请求如果同时有几万个用户调用APIGPU直接就被打满了服务直接崩溃。这时候就可以用队列把用户的请求先放到队列里按GPU的处理能力一个个取出请求处理既保证了服务不崩溃还能给VIP用户设置优先队列优先处理他们的请求简直完美。3.2.2 广度优先搜索BFS算法的核心自动驾驶路径规划全靠它队列还有一个核心的应用场景就是广度优先搜索BFS这个是算法里的核心不管是二叉树的层序遍历还是迷宫的最短路径查找还是自动驾驶的路径规划都是用队列实现的。通俗讲一下BFS的逻辑比如你要走迷宫从起点到终点找最短的路径。BFS的做法就是从起点出发先把起点周围能走的格子全部加入队列里然后从队列里取出第一个格子再把这个格子周围能走的、没走过的格子加入队列的尾部就这样一层层遍历先遍历的格子先处理完美符合队列的先进先出原则。一旦找到终点就是最短的路径因为BFS是一层一层找的最先找到的终点一定是步数最少的。2026年了自动驾驶的路径规划、机器人的导航、大模型的知识图谱检索底层全是BFS算法也就是队列的核心逻辑你说队列重不重要3.2.3 大模型解码核心beam search束搜索底层就是优先队列前面讲优先队列的时候提到了beam search这个是所有生成式大模型解码的核心算法2026年了不管是GPT还是文心一言底层解码都用了这个算法而它的底层就是优先队列实现的。给兄弟们通俗讲一下大模型生成文本的时候是一个token一个token生成的每生成一个token都会预测下一个token的概率。如果每次只选概率最高的那一个token就是贪心搜索很容易生成重复、不通顺的文本。而beam search就是每次都保留前K个概率最高的候选序列这个K就是束宽。怎么高效的保留前K个概率最高的候选序列就是用优先队列每次生成新的候选序列都把它加入优先队列里优先级就是序列的总概率每次只保留前K个概率最高的剩下的全部丢掉这样既能保证生成的文本通顺又不会有太大的计算量。很多人天天用大模型却不知道底层是这么基础的优先队列你把这个原理讲给面试官听面试官直接就知道你不是只会调包的API调用工程师而是真的懂底层原理。四、面试被问栈和队列直接慌2026年最高频的5道经典面试题手把手给你讲明白我在AI行业摸爬滚打了22年面过太多候选人也看过太多大厂的面试题栈和队列的面试题翻来覆去就这5道是个公司面试就会考我今天手把手给你讲明白思路、代码、面试追问的坑全给你说透背完直接拿捏面试官。4.1 面试题1用两个栈实现队列剑指Offer原题10个公司面试9个考题目用两个栈实现一个队列支持队列的基本操作入队enqueue、出队dequeue。解题思路很多人看到这个题第一反应就是懵两个后进先出的栈怎么实现一个先进先出的队列其实非常简单就像你有两个桶一个桶用来装水一个桶用来倒水两个桶倒来倒去顺序就反过来了。我给你通俗讲明白我们准备两个栈一个叫in栈专门负责入队一个叫out栈专门负责出队。入队操作非常简单直接把数据push到in栈里就行啥也不用管出队操作这里是核心分两步第一步如果out栈是空的就把in栈里的所有元素全部一个个pop出来再一个个push到out栈里。这时候你会发现in栈里的元素是先进后出倒到out栈里之后顺序就完全反过来了原来in栈里最先入队的元素现在到了out栈的栈顶第二步直接把out栈的栈顶元素pop出来就是队列里最先入队的元素完美实现了先进先出。这里有个面试必追问的坑只有当out栈是空的时候才能把in栈里的元素倒过去如果out栈里还有元素绝对不能倒不然顺序就乱了。比如你入队了1、2、3in栈里是[1,2,3]倒到out栈里变成[3,2,1]这时候你出队了1out栈里还有[3,2]这时候你又入队了4直接push到in栈里in栈里是[4]这时候绝对不能把4倒到out栈里不然out栈就变成[3,2,4]再出队就会出4而不是2顺序就乱了。Python代码实现classMyQueue:def__init__(self):# 初始化两个栈in栈负责入队out栈负责出队self.in_stack[]self.out_stack[]defenqueue(self,x:int)-None:# 入队直接往in栈里pushself.in_stack.append(x)defdequeue(self)-int:# 如果out栈是空的就把in栈里的所有元素倒到out栈里ifnotself.out_stack:whileself.in_stack:self.out_stack.append(self.in_stack.pop())# 出队就是out栈的popreturnself.out_stack.pop()defpeek(self)-int:# 取队头元素和出队逻辑一样只是不popifnotself.out_stack:whileself.in_stack:self.out_stack.append(self.in_stack.pop())returnself.out_stack[-1]defisEmpty(self)-bool:# 两个栈都空队列才是空的returnnotself.in_stackandnotself.out_stack4.2 面试题2用两个队列实现栈和上面的题成对出现面试必问题目用两个队列实现一个栈支持栈的基本操作入栈push、出栈pop。解题思路这个题和上面的题刚好反过来两个先进先出的队列实现一个后进先出的栈。核心思路就是用两个队列一个主队列一个辅助队列入栈的时候直接往主队列里放出栈的时候把主队列里除了最后一个元素之外的所有元素全部转移到辅助队列里剩下的最后一个元素就是栈顶元素直接出队就行然后把主队列和辅助队列交换下次继续用。通俗讲一下比如你入栈了1、2、3主队列里是[1,2,3]现在要出栈需要把最后入栈的3拿出来你就把1、2从主队列里出队放到辅助队列里主队列里就剩下3了把3出队就是出栈操作然后把主队列和辅助队列交换现在主队列是[1,2]辅助队列是空的下次入栈继续往主队列里放就行。还有一个优化的思路用一个队列就能实现栈入队的时候把队列里前面的所有元素全部出队再入队把新入队的元素放到队头这样出队的时候就是后进先出了代码更简单面试的时候说出来直接加分。Python代码实现两个队列版本fromcollectionsimportdequeclassMyStack:def__init__(self):# 初始化两个队列self.main_queuedeque()self.help_queuedeque()defpush(self,x:int)-None:# 入栈直接往主队列里入队self.main_queue.append(x)defpop(self)-int:# 把主队列里除了最后一个元素全部转移到辅助队列whilelen(self.main_queue)1:self.help_queue.append(self.main_queue.popleft())# 主队列里剩下的最后一个元素就是栈顶元素resself.main_queue.popleft()# 交换主队列和辅助队列self.main_queue,self.help_queueself.help_queue,self.main_queuereturnresdeftop(self)-int:# 取栈顶元素和出栈逻辑一样只是要把元素放回去whilelen(self.main_queue)1:self.help_queue.append(self.main_queue.popleft())resself.main_queue.popleft()self.help_queue.append(res)self.main_queue,self.help_queueself.help_queue,self.main_queuereturnresdefempty(self)-bool:returnnotself.main_queuePython代码实现单队列优化版本fromcollectionsimportdequeclassMyStack:def__init__(self):self.queuedeque()defpush(self,x:int)-None:# 先把新元素入队self.queue.append(x)# 把前面的所有元素全部出队再入队把新元素放到队头for_inrange(len(self.queue)-1):self.queue.append(self.queue.popleft())defpop(self)-int:# 队头就是栈顶直接出队returnself.queue.popleft()deftop(self)-int:returnself.queue[0]defempty(self)-bool:returnnotself.queue4.3 面试题3有效的括号LeetCode第20题入门必刷面试100%会考题目给定一个只包括 ‘(’‘)’‘{’‘}’‘[’‘]’ 的字符串判断字符串是否有效。有效字符串需满足左括号必须用相同类型的右括号闭合左括号必须以正确的顺序闭合每个右括号都有一个对应的相同类型的左括号。解题思路这个题就是栈最经典的应用前面讲应用场景的时候已经给大家讲过核心逻辑了这里再给大家梳理一遍还有面试常问的坑。核心逻辑先建一个哈希表把右括号和对应的左括号映射起来比如’)‘对应’(, ‘}‘对应’{’, ‘]‘对应’[’这样遇到右括号的时候直接就能找到对应的左括号初始化一个栈遍历字符串里的每个字符如果是左括号直接入栈如果是右括号先看栈是不是空的如果是空的说明没有对应的左括号直接返回False如果栈不是空的取出栈顶元素看是不是和当前右括号对应的左括号一致一致就出栈不一致直接返回False遍历完所有字符之后看栈是不是空的如果是空的说明所有括号都匹配成功返回True否则返回False。这里有几个面试常问的坑如果字符串的长度是奇数直接返回False因为括号必须成对奇数个肯定有一个匹配不上提前判断能节省时间遇到右括号的时候栈是空的直接返回False比如字符串是)(){}第一个字符就是右括号肯定无效遍历完之后栈不是空的说明有左括号没有匹配的右括号比如字符串是({)}遍历完栈里还有元素无效。Python代码实现defisValid(s:str)-bool:# 如果长度是奇数直接返回Falseiflen(s)%2!0:returnFalse# 建立右括号到左括号的映射bracket_map{):(,}:{,]:[}# 初始化栈stack[]forcharins:# 如果是右括号ifcharinbracket_map:# 栈空的话直接返回False否则取栈顶元素top_elementstack.pop()ifstackelse## 不匹配直接返回Falseifbracket_map[char]!top_element:returnFalse# 如果是左括号入栈else:stack.append(char)# 最后栈空才是有效returnnotstack4.4 面试题4滑动窗口最大值LeetCode第239题中大厂必考题字节腾讯最爱考题目给你一个整数数组 nums有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。返回滑动窗口中的最大值。解题思路这个题暴力解法很简单就是每个窗口都遍历一遍找最大值但是时间复杂度是O(n*k)如果数组很大k也很大直接就超时了面试的时候写暴力解法面试官直接就给你挂了。最优的解法就是用双端队列实现时间复杂度直接降到O(n)也是面试的时候面试官想看到的解法。核心思路我们用一个双端队列队列里存的是数组的下标不是数值而且要保证队列里的下标对应的数值是从大到小严格递减的。遍历数组里的每个元素下标是i第一步清理队尾。如果队列不为空而且当前元素nums[i]大于等于队尾下标对应的数值就把队尾的下标移除因为它不可能成为任何窗口的最大值了有比它大的、还比它晚过期的元素在它永远没有出头之日直到队列为空或者队尾下标对应的数值大于当前元素然后把当前下标i加入队尾第二步清理队头。判断队头的下标是不是已经不在当前的窗口里了也就是队头的下标 i - k如果是就把队头的下标移除因为它已经过期了不在窗口里了第三步记录结果。当i k - 1的时候说明窗口已经形成了队头的下标对应的数值就是当前窗口的最大值加入结果数组里。通俗讲一下这个双端队列就像一个“候选人大厅”每次来一个新的候选人先把大厅里比他弱的、没他能打的全部赶出去因为有他在这些人永远当不上最大值然后他再进去同时把已经过期的、不在窗口里的候选人从门口赶出去最后大厅门口的那个人就是当前窗口里最能打的也就是最大值。Python代码实现fromcollectionsimportdequedefmaxSlidingWindow(nums:list[int],k:int)-list[int]:# 初始化双端队列和结果数组deque_windowdeque()res[]foriinrange(len(nums)):# 清理队尾把比当前元素小的全部移除whiledeque_windowandnums[i]nums[deque_window[-1]]:deque_window.pop()# 把当前下标加入队尾deque_window.append(i)# 清理队头移除已经过期的下标whiledeque_window[0]i-k:deque_window.popleft()# 窗口形成记录最大值ifik-1:res.append(nums[deque_window[0]])returnres4.5 面试题5TOP K问题海量数据找前K大的数互联网公司必问AI领域高频题目给你一个无序的数组找出其中前K大的数进阶如果是10亿个数字内存放不下怎么找前K大的数解题思路这个题是面试的超高频题不管是后端岗还是AI算法岗必考因为它的应用场景太广了大模型的beam search、推荐系统的热门商品排序、海量数据的统计都用得到。最优的解法就是用**小顶堆优先队列**实现时间复杂度是O(nlogK)比排序的O(nlogn)快太多尤其是n很大K很小的时候优势非常明显。核心思路我们维护一个大小为K的小顶堆堆顶的元素是堆里最小的那个也就是当前前K大的数里最小的那个。遍历数组里的每个元素如果堆的大小小于K直接把当前元素加入堆里如果堆的大小已经等于K了就比较当前元素和堆顶的元素如果当前元素比堆顶元素大说明当前元素能进前K就把堆顶的元素移除把当前元素加入堆里如果当前元素比堆顶元素小说明它进不了前K直接跳过遍历完整个数组之后堆里的K个元素就是数组里前K大的数。很多人会问为啥用小顶堆不用大顶堆因为大顶堆的话你要维护所有元素的大顶堆取前K个时间复杂度是O(nlogn)而且如果是海量数据内存根本放不下而小顶堆只需要维护大小为K的堆内存占用非常小就算是10亿个数据也能一个个遍历不用一次性加载到内存里完美解决海量数据的问题。对于海量数据的进阶问题还有一个分治法的思路把10亿个数字分成很多份每份都能加载到内存里每份都找出前K大的数然后把所有份的前K大的数合并起来再找总的前K大的数这个也是面试的时候会追问的你说出来面试官直接对你刮目相看。Python代码实现Python里的heapq模块实现的就是小顶堆直接用就行。importheapqdeftopK(nums:list[int],k:int)-list[int]:# 初始化小顶堆heap[]fornuminnums:# 堆的大小小于k直接加入iflen(heap)k:heapq.heappush(heap,num)else:# 当前元素比堆顶大替换堆顶ifnumheap[0]:heapq.heappop(heap)heapq.heappush(heap,num)# 堆里的元素就是前K大的数returnheap五、最后说几句掏心窝子的话2026年了AI行业发展的太快了大模型、智能体、AIGC各种新名词层出不穷很多人都在焦虑怕自己跟不上风口被行业淘汰于是疯狂的学各种框架、调各种API觉得自己掌握了最前沿的技术。但我在AI行业摸爬滚打了22年见过太多的技术风口从最早的专家系统到机器学习再到深度学习再到现在的大模型技术一直在变但是底层的逻辑从来没变过。不管是多高大上的大模型底层的算子调度、推理逻辑、解码算法全是栈、队列、树、图这些最基础的数据结构和算法撑起来的。太多人一心追着风口跑却忘了打地基就像建房子地基都没打牢就想盖摩天大楼风一吹就倒了。你只会调大模型的API不会优化底层逻辑遇到问题根本不知道怎么解决面试的时候面试官一问底层原理你就哑火那你永远只能做个API调用工程师随时都能被替代。栈和队列是数据结构里最基础、最简单的内容也是你入门算法、学好AI的第一步你把这个搞透了后面的二叉树、动态规划、深度学习的底层逻辑都会事半功倍。希望这篇文章能帮你真正把栈和队列搞明白也希望兄弟们能沉下心来把基础打牢不要被风口带着跑只有基础扎实了你才能在技术的浪潮里站稳脚跟不被淘汰。P.S. 目前国内还是很缺AI人才的希望更多人能真正加入到AI行业共同促进行业进步增强我国的AI竞争力。想要系统学习AI知识的朋友可以看看我精心打磨的教程 http://blog.csdn.net/jiangjunshow教程通俗易懂高中生都能看懂还有各种段子风趣幽默从深度学习基础原理到各领域实战应用都有讲解我22年的AI积累全在里面了。注意教程仅限真正想入门AI的朋友否则看看零散的博文就够了。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价