阿里巴巴实习生笔试真题全解析:从TCP三次握手到动态规划备考指南

发布时间:2026/8/30 9:15:40
阿里巴巴实习生笔试真题全解析:从TCP三次握手到动态规划备考指南 聊到阿里巴巴的实习生笔试题2017年这批算是我印象里很有代表性的一套。我当时为了准备暑期实习在牛客网把这些题翻来覆去刷了好几遍后来带学弟学妹做模拟面试也经常拿其中几道当试金石。这套题有个特点不考偏门知识点但特别考验基础功底扎不扎实。计算机网络、操作系统、数据结构与算法三块加起来能占到六七成剩下的是逻辑推断和简单的场景设计。如果你正准备投大厂技术岗实习或者想进互联网行业但对笔试题型没底这篇文章可以给你一份很落地的自测清单。1. 2017年实习生笔试的整体结构与考点分布1.1 试卷长什么样2017年的阿里巴巴实习生笔试是线上笔试我当时印象里是牛客网这套系统总共60分钟到90分钟题量不算小。试题结构大致是单选题15道左右、多选题5道左右然后是一两道编程题偶尔会夹带一道简答题或者场景设计题。这种结构决定了策略跟校招笔试不太一样——基础题占比高编程题题目量少但分值重所以基础题能不能少丢分基本决定了你能不能进一面。我当时拿到卷子的第一感受是单选题考得很细但都是“应该会”的题。比如TCP三次握手、进程线程区别、Java内存模型、Linux命令、二叉树的遍历这些在教学里都讲过但考的是你有没有真正理解而不是死记硬背概念。编程题则是一道纯字符串处理、一道动态规划或者滑动窗口类的题难度适中比LeetCode中等题略低但要求在限定时间内写完且跑通边界用例。1.2 考点权重哪块内容最容易被翻牌从当年的真题分布来看我将考点大致分成四个模块模块常见题型大致占比典型知识点计算机基础单选、多选30% - 40%TCP/IP、HTTP、进程线程、内存管理、Linux命令数据结构与算法单选、编程30% - 40%二叉树、哈希、排序、动态规划、滑动窗口逻辑推理单选、问答10% - 15%烧绳子、称球、逻辑推理题场景设计简答10% - 15%秒杀系统、短URL、缓存设计这个分布说明了一个问题阿里实习生笔试不太纠缠于偏门框架或源码级细节它更看重你是否有扎实的计算机基础以及能不能用代码解决实际问题。很多人复习时喜欢追热点技术比如什么新框架新中间件但笔试反而容易被一个三次握手问题卡住。所以准备时基础知识的优先级一定要排在框架前面。1.3 这些考点背后的筛选逻辑为什么阿里的笔试要这么设计从面试官的角度看实习生进来后做的第一件事不是写复杂业务而是看代码、改bug、写小功能这些工作需要的不是你会多少框架而是你网络、操作系统、数据结构的基本功是否可靠。比如线上服务超时了你要能根据网络原理判断是连接建立慢还是请求处理慢内存涨上去了你得能联想到GC、页面置换、缓存过期这些机制。这些就是笔试考点背后的真实业务映射。2. 计算机基础题网络与OS的经典送分与送命题2.1 TCP三次握手为什么是三次不是两次这是阿里笔试选择题里的常客当年也考了。题目一般是“下列关于TCP三次握手的说法正确的是”或者“为什么TCP建立连接需要三次握手两次行不行”。很多人能背出SYN、SYNACK、ACK的过程但问“为什么不是两次”就卡住了。三次握手要解决两个核心问题第一同步双方的初始序列号第二确认双方的收发能力都正常。第一次握手客户端发出SYN服务端收到后能确认客户端发送能力正常。第二次握手服务端回复SYNACK客户端收到后能确认服务端收发能力都正常但此时服务端还不知道客户端接收能力是否正常。所以需要第三次握手客户端再回一个ACK服务端收到后就能确认客户端接收能力正常。这样双方才都对彼此的信道有了确认。那两次行不行从单次连接建立来看两次确实能建立连接但存在一个很要命的问题旧的重复SYN会让服务端白白建立一条无效连接。举个具体场景客户端发起一个SYN因为网络拥塞迟迟没到客户端超时重传了一个新的SYN服务端正常回SYNACK并建立连接然后业务跑完关闭。结果那个旧SYN这时才到达服务端服务端以为是个新连接请求回复SYNACK并分配资源。如果没有第三次握手服务端会一直等着这个连接上的数据直到超时才释放资源就被白白占用了。有了第三次握手客户端收到服务端对这个旧SYN的SYNACK后发现ACK序号不是自己期望的就会回一个RST服务端收到RST后主动关闭资源立刻释放。所以三次是保证可靠性的最小握手次数。2.2 进程与线程一道题串起整个OS核心很多多选题喜欢把进程和线程混在一起问让你选正确的说法。我记得当时的题目选项大概包括线程是CPU调度的基本单位、进程是资源分配的基本单位、线程崩溃会导致整个进程崩溃、进程并发执行比线程开销大。这些说法基本都对但有的会在细节上下套。进程和线程最本质的区别在于资源粒度。进程是资源分配的基本单位每个进程有独立的虚拟地址空间、页表、文件描述符表、信号处理状态。线程是CPU调度的基本单位同一个进程下的多个线程共享代码段、数据段、堆、打开的文件但每个线程有自己独立的栈、寄存器上下文和程序计数器。我在实际准备时习惯用一张表来对比对比项进程线程资源分配独立地址空间共享进程资源调度早期以进程为单位现代OS以线程为调度单位切换开销大需要切换页表、刷新TLB小只需保存/恢复寄存器上下文通信需用管道、消息队列、共享内存、信号量等IPC直接读写共享内存但需同步稳定性一个进程崩溃不影响其他一个线程崩溃可能导致整个进程崩溃这个表里的关键点是“切换开销”。为什么线程切换比进程切换便宜因为线程切换不需要切换页表地址空间不变CPU的TLB缓存还能继续用进程切换则要切换页表TLB很可能失效下次访问内存的耗时就会增加。笔试如果考这类细节你要能说出这一层而不只是“线程轻量、进程重量”这种表面答案。2.3 页面置换FIFO与LRU的Belady异常操作系统里的页面置换算法也是高频考点。阿里笔试一般不会让你写出完整代码而是给你一个页面访问序列和物理块数问你缺页次数。这里有个非常经典的例题我几乎每次讲都会拿出来访问序列1 2 3 4 1 2 5 1 2 3 4 5物理块数3。如果按FIFO先进先出来置换缺页次数是9次按LRU最近最少使用来置换缺页次数是10次按OPT理想淘汰算法淘汰未来最久不用的来置换缺页次数是7次。这个例子好玩的地方在于FIFO居然比LRU表现还好这并不常见它是反直觉的一个特例。提示这个序列是教科书里著名的Belady异常例子。Belady异常指的是当物理块数增加时FIFO算法的缺页次数反而可能增多而LRU是栈算法不会出现这种异常。为什么LRU是栈算法就不会有Belady异常所谓栈算法是指当访问一个页面时被访问页面位于栈顶LRU维护的最近使用顺序始终是单调的物理块数的增加只是让栈可容纳的页面数变多不会破坏已有页面的相对优先级。而FIFO队列不是栈新增物理块会改变淘汰顺序可能导致原本不会淘汰的页面被淘汰了。这个点如果在笔试里能写出来是会加分的。2.4 Linux命令别在这种题上翻车Linux命令在笔试里属于送分题但每年都有人翻车。原因是大家平时用IDE或者Windows开发对常用命令停留在“听说过”的程度。其实阿里的笔试考得很常规一般就是让你选哪个命令能查看磁盘占用、哪个能实时查看日志。我整理了一个最常用速查表考前扫一眼就能覆盖大部分考点场景命令说明查看磁盘空间df -h查看各分区使用情况-h是human-readable查看内存free -m以MB为单位显示内存和swap使用量查找文件find /path -name *.log按名称查找文件文本搜索grep -rn keyword /path递归搜索带关键字的行查看端口占用netstat -tlnp查看TCP监听端口和对应进程查看进程ps -ef / topps 是静态快照top 是实时更新实时查看日志tail -f app.log跟踪日志尾部新增内容其中tail -f是排查线上问题的高频命令很多笔试场景题会结合这个命令来出线上日志一直在刷ERROR你该怎么快速定位。答出一句tail -f加上grep按关键字过滤基本能看出你不是纯背命令而是真的排过障。3. 数据结构与算法笔试拉开差距的主战场3.1 二叉树非递归遍历的套路二叉树遍历在阿里笔试里一般不会直接考“请写出中序遍历”而是结合选择题考非递归实现的思想或者让你在编程题里用层级遍历解决某个问题。我当时遇到的是一道选择题问“下列哪种方式可以实现二叉树中序的非递归遍历”选项里有栈、队列、递归、哈希表。递归遍历很简单但非递归手动模拟需要理解一点递归的本质是函数调用栈帮你保存了“当前节点处理到哪一步”的状态非递归就是自己用栈来保存这个状态。前序和中序的非递归实现思路很接近沿着左子树一路入栈直到空节点然后出栈访问节点再转到右子树。区别只在于访问节点的时间点前序在入栈前就访问中序在出栈后访问。后序非递归要复杂一些因为需要在左子树和右子树都处理完后才能访问根节点。经典做法是使用两个栈第一个栈按照“根-右-左”的顺序压栈弹出来的节点压进第二个栈最后把第二个栈依次弹出得到的就是“左-右-根”的后序序列。这个方法很巧妙也好记忆笔试时如果考到能写出来会显得你理解得很透。3.2 哈希冲突和布隆过滤器哈希是数据结构里性价比很高的一块笔试既考概念又考应用。基础考点是哈希冲突的解决方式链地址法和开放地址法。链地址法就是把哈希到同一个槽位的元素用链表串起来Java的HashMap就是这么做的开放地址法在冲突时继续探测下一个空位包括线性探测、平方探测、双重哈希。有一道常考的选择题HashMap为什么默认负载因子是0.75而不是0.5或1.0。这背后其实是时间和空间的权衡。负载因子越小冲突概率越低但表占用的空间越大扩容越频繁负载因子接近1空间利用率高但冲突概率显著增大链表变长查找退化到O(n)。0.75是JDK设计者在大量测试基础上选的折中值。笔试时你能答出“时间与空间的折中”基本就得分了。布隆过滤器也偶尔会出现在选择题或场景题里。它的原理是用k个哈希函数把一个元素映射到位数组的k个位置并置为1。查询时看这k个位置是否都为1只要有一个为0那元素一定不存在如果都为1可能不存在也可能存在也就是有误判率。它最大的优点是用很少的内存判断“一定不存在”缺点是存在误判且不能删除元素。我在准备时把它跟“缓存穿透”联系起来记数据库前加一层布隆过滤器如果布隆说这个key不存在就直接返回不用查库能挡住大量恶意请求。3.3 0-1背包问题的动态规划0-1背包是算法笔试里的常青树阿里实习生笔试也喜欢出这类题只不过会换一个场景包装比如“搭配合适的套餐组合使总价值最大”之类。核心模型就一个有N件物品每件物品重量w[i]、价值v[i]背包容量W求能装下的最大价值。每件物品只能选0次或1次。状态定义dp[i][j]表示前i件物品在容量为j的背包中能获得的最大价值。转移方程dp[i][j] max(dp[i-1][j], dp[i-1][j-w[i]] v[i]) (j w[i])意思就是第i件物品要么不拿继承前i-1件的结果要么拿腾出w[i]的容量再加上v[i]的价值。初始状态dp[0][j]0。笔试里更常考的是空间优化也就是用一维数组滚动更新让dp[j]表示容量j时的最大价值。但注意内层循环必须从W往w[i]逆序遍历。为什么因为一维数组只有一个dp[j]如果正序遍历更新dp[j]时用到的dp[j-w[i]]可能已经是当前物品更新过的值相当于同一件物品被重复放入了这就退化成了完全背包。逆序则保证dp[j-w[i]]还是上一轮的状态也就是说每件物品最多选一次。能把这个道理讲清楚比单纯写出代码更让面试官满意。我当年刷到一个具体例子可以拿来手算一遍背包容量10四件物品分别是重量5价值12、重量4价值8、重量6价值15、重量3价值6。用一维dp从大到小更新后最终dp[10]等于23对应的方案是选第2件重4值8和第3件重6值15总重量10总价值23。这个结果不算难但如果你没理解一维数组的更新顺序很容易算成22甚至20。3.4 最长上升子序列从O(n^2)到O(nlogn)编程题里动态规划还有一种常见考法就是最长上升子序列LIS。比如给一个序列3 1 4 1 5 9 2 6 5求最长严格上升子序列的长度。答案是4比如1 4 5 9或1 2 5 6。最直接的dp思路是dp[i]表示以第i个元素结尾的最长上升子序列长度。初始化每个dp[i]1然后遍历i之前的所有j只要nums[j] nums[i]就尝试dp[i] max(dp[i], dp[j] 1)。最终答案就是整个dp数组的最大值。时间复杂度O(n^2)。如果数据范围到10^5O(n^2)就会超时需要用贪心二分优化到O(nlogn)。思路是维护一个tails数组tails[k]表示长度为k的上升子序列中末尾元素的最小值。遍历原序列对每个x在tails中二分查找第一个大于等于x的位置把它替换成x如果x比所有tails元素都大就追加到末尾。这个做法的核心是相同长度的子序列末尾元素越小后面越容易接上更长的子序列所以每次都用更小的末尾值去替换就能贪心地让整个序列更容易变长。这个优化思路笔试时不一定要求写出来但如果你能写出来绝对是一个亮点。4. 逻辑推理与场景设计题笔试里的“隐藏加分项”4.1 烧绳子问题经典中的经典逻辑推理题在阿里笔试里占比不大但出现次数很稳定。最经典的就是“烧绳子计时”问题有两根不均匀的绳子每根烧完都需要60分钟但燃烧速度不均匀不能用“烧一半就是30分钟”来切分请问如何用这两根绳子测出45分钟。解法是第一根绳子两头同时点燃第二根绳子只点燃一头。第一根两头点燃后不管燃烧速度多不均匀30分钟一定烧完。第一根烧完的瞬间立刻把第二根绳子的另一头也点燃。第二根绳子此时已经烧了30分钟剩余部分如果继续一头烧还能烧30分钟现在两头一起烧剩余部分就会在15分钟内烧完。所以从开始到第二根烧完总共是301545分钟。这个题的关键是“两头点燃”可以固定燃烧时长不管绳子多不均匀整根烧完时间的一半就是两头点燃所需时间。这类题考的不是数学而是你能否跳出“必须从一头烧”的思维定式。笔试里遇到不要慌把“两头点燃”这个工具记住很多计时题都能解出来。4.2 秒杀系统怎么答才不丢分场景设计题在实习生笔试题里不算难我印象里就问过类似“设计一个秒杀系统如何防止超卖”这样的题。很多人看到就头疼其实答题有套路分层次说清楚数据流就能拿分。先说明整体架构然后分别说每层怎么做前端层按钮提交后置灰防止用户疯狂点击加图形验证码或滑块验证拦掉一部分机器请求秒杀页面静态化并上CDN降低源站压力。网关层在Nginx或API网关做IP维度、用户维度的限流比如单个用户每秒最多1个请求。库存层用Redis预减库存。用户请求先到Redis通过Lua脚本原子地执行“检查库存大于0然后减库存”的操作。Lua脚本能保证原子性避免并发下多个请求同时读到库存为1结果都减成功导致超卖。消息队列减库存成功的请求扔进MQ由后端异步下单、异步扣款。MQ在这里起到削峰填谷的作用避免瞬时流量直接打到数据库。数据库层数据库负责最终一致性扣减用乐观锁或唯一索引保证同一用户同一商品只能成功下一单。幂等用户可能重复提交后端需要做幂等判断比如用user_idgoods_id做唯一索引第一次插入成功后续重复插入失败。答题时不要说“用Redis就完了”要讲清楚Redis在哪个环节、解决了什么问题、数据库如何兜底。我当时答题用了这个分层思路虽然没有写得很深但面试官反馈说“有整体意识”这就是场景题的核心得分点。5. 编程题原题复盘送分题也要写出规范5.1 字符串压缩这是我印象里那年的一道编程题题目大意是输入一个字符串比如aabcccccaaa把它压缩成a2b1c5a3也就是“字符连续出现次数”的格式。如果压缩后的字符串长度不小于原串长度则返回原串。这道题本身不难但很考验边界处理的严谨性。我当时写的Python版本是这样的def compress_string(s): if not s: return res [] cnt 1 for i in range(1, len(s)): if s[i] s[i - 1]: cnt 1 else: res.append(s[i - 1] str(cnt)) cnt 1 res.append(s[-1] str(cnt)) compressed .join(res) return compressed if len(compressed) len(s) else s这里有三个容易踩的坑一是空字符串不做判断直接访问s[-1]会越界必须单独处理二是连续相同字符出现在末尾循环结束后最后一个字符的计数还没拼接需要额外append一次三是压缩后可能比原串还长比如abcd压缩后是a1b1c1d1比原串长要返回原串。这三个坑笔试时至少有一个会被用例踩中。我后来带人时反复强调程序题写得对不算本事写得边界全对才算。5.2 最长无重复子串另一道常考的编程题是LeetCode第三题的原型给定一个字符串找出其中不含有重复字符的最长子串的长度。比如abcabcbb最长无重复子串是abc长度3bbbbb长度1。这题的标准解法是滑动窗口哈希集合。窗口用两个指针left和right维护right不断右移扩展窗口每遇到一个新字符就检查它是否已经在窗口集合里。如果在就不断把left往右移同时从集合里删除移出窗口的字符直到重复字符被移出。然后加入当前字符更新答案。代码如下def length_of_longest_substring(s): window set() left 0 ans 0 for right, ch in enumerate(s): while ch in window: window.remove(s[left]) left 1 window.add(ch) ans max(ans, right - left 1) return ans这里有一个很多人会犯的错while循环里移除的是s[left]而不是ch本身。因为你要删除的是“窗口里和ch重复的那个字符”及其前面的所有字符而窗口里的字符并不是按重复关系组织的只能用left指针从前往后逐个删除。如果你只是remove(ch)可能ch会出现多次但集合里只有一个ch移除后窗口逻辑就乱了。另外这道题最优解的时间复杂度是O(n)因为每个字符最多被加入和移除一次空间复杂度O(min(n, 字符集大小))。笔试时如果时间紧张甚至可以先写一个O(n^2)的暴力解保底然后跟面试官说明可以优化。但作为准备充分的人滑窗解法应该是直接默写出来的水平。6. 高频失分点与备考建议6.1 笔试中最容易踩的坑我刷了那么多套题也看了很多人的复盘发现大家失分最多的不是不会做而是踩了下面这几个坑第一边界条件漏处理。编程题里空指针、空字符串、数组越界、溢出几乎每道题都能找到对应的边界坑。很多人写完代码不检查边界就直接交卷结果用例跑不过。我的习惯是写完代码后固定花30秒检查输入为空时函数能不能正常返回、循环结束后的最后一个元素有没有被处理、整型运算会不会溢出。第二选择题不确定却乱猜。阿里笔试有些选择题是倒扣分或者按题目难度加权分配的具体规则要看当年说明。如果不确定不要随便蒙尤其是多选题少选可能比错选更划算。我当时的原则是多选题只选百分百确定的选项模棱两可的不选。第三时间复杂度说不清楚。编程题写完了面试官追问“你的时间复杂度是多少能不能优化”很多人就卡住了。所以刷题时不要只看题解要自己分析每道题的复杂度和瓶颈。特别是能用二分、滑动窗口、双指针解决的题要把优化思路一并整理。第四场景题堆名词不给流程。一说到秒杀就写“Redis、MQ、缓存、限流”但没说明数据怎么流转。面试官想看的不是你会背名词而是你能说清楚一个请求从进入到完成每一步的组件和职责。6.2 90分钟实战时间分配建议当年笔试时间并不宽裕我的做题节奏可以供你参考前10分钟快速浏览全部题目标记出有把握的选择题和编程题。不要在第一题上死磕太久。第10到50分钟做基础选择题和逻辑题。优先做计算机网络、操作系统、数据结构这类确定性高的题每道题控制在1到2分钟内。遇到不会的先标记跳过不恋战。第50到80分钟做编程题。每道编程题最多给自己15到20分钟。如果15分钟还没有完整思路先用暴力解法写一版保证有分然后再想优化。第80到90分钟检查。重点复查选择题有没有看错选项、代码有没有语法错误、边界用例有没有覆盖、有没有漏题。这个节奏的前提是基础题要足够熟练。如果你在三次握手、进程线程这类题上还要想半天说明基础还需要补。把《深入理解计算机系统》的虚拟内存和异常控制流章节、《计算机网络》的TCP章节、以及常见算法模板刷熟练比临考前突击一百道偏题更有效。6.3 备考资料的取舍与实战练习最后说说资料。我当时准备阿里笔试主要用了三类资料一是《剑指Offer》编程题从头到尾手写了一遍这本书里的题目难度和阿里实习生编程题非常接近二是LeetCode高频100题重点刷数组、字符串、链表、二叉树、动态规划、滑动窗口这些类型三是牛客网的历年笔试真题用来刷手感并适应在线笔试的代码提交方式。有一点需要特别提醒刷题一定要动手写不要只看题解。我当时有个教训看“最长无重复子串”的题解觉得很容易结果自己写的时候在while循环的删除逻辑上卡了20分钟。后来我规定自己任何一道题必须先把代码写出来再对答案错了就再写一遍直到能独立通过全部用例为止。这个过程虽然慢但效果很好笔试时遇到类似题目基本是条件反射。除了刷题我还把阿里的开源项目和云产品文档当“课外读物”。为什么因为笔试里有些场景题比如缓存设计、消息队列削峰、服务限流你如果看过阿里云上相关产品的架构文档答题时思路会清晰很多会知道真实工业界是怎么做的而不只是教科书里的理论方案。备考期间可以抽空搜一搜阿里的技术博客看看他们怎么介绍中间件和架构演进对场景题很有帮助。一点后话写到这里我想起当时笔试前自己最担心的不是算法题反而是那些“看起来简单”的基础选择题。后来经历告诉我这种担心是对的——基础题才是区分度最大的地方。算法题大家都会刷但TCP为什么需要三次握手、线程栈为什么不能共享、页面置换里的Belady异常是怎么回事这些细节恰恰是平时容易一带而过的地方。如果你正在准备类似的实习生笔试我建议你拿出一周时间把计算机网络和操作系统的核心概念过一遍重点是能用自己的话解释清楚“为什么”。然后每天保证手写两到三道算法题写完后检查边界。这种组合准备下来不管是阿里还是其他大厂笔试的通过率都会有一个明显提升。祝你好运。