
每年三到五月互联网行业的实习生招聘都会进入一个密集出题期。2017年的阿里春招也不例外第二场笔试题集二当时在应届生里讨论度很高。它和第一批次题目最明显的区别在于——不是更难而是更“碎”客观题覆盖面广编程题难度梯度拉得比较开最后还有一道选做附加题。很多同学把精力全压在算法上最后反而在客观题环节丢掉太多分。这篇文章不打算只给一套答案而是从出题逻辑、题型分析、做题顺序到判题环境的完整复盘帮各位准备一线大厂实习笔试时少走弯路。1. 当年那场笔试到底考了什么先看清试卷结构再谈刷题1.1 为什么说实习生笔试拼的并不是算法天花板我见过不少准备实习笔试的同学一上来就钻进LeetCode的困难题里觉得只有做难题才能进大厂。但等到真的上了考场你会发现实习生笔试筛选的核心指标根本不是“你会不会难题”而是“你在有限时间内能不能稳定输出基础能力”。2017年阿里实习生笔试二的题目体系我根据当时参加的同学反馈和自己整理的题目印象整体是这样分布的单选题覆盖数据结构、网络、操作系统、Java/C基础多选题主要考概念辨析和边界细节简答题会问你某个场景下会选用什么技术方案最后两道到三道编程题难度从签到题到中等偏上不等。附加题通常不强制完成但做出来会有额外加分。这个结构说明一个问题出题人默认你是来实习的不是来参加算法竞赛的。实习生进组之后要先能在业务代码里看懂逻辑、能处理边界情况、能在别人留下的代码基础上快速改需求。所以笔试里会大量出现“场景题”把知识点包装成一段业务描述问你哪个方案最合理。单纯会背“红黑树查找时间复杂度是O(log n)”没用你得知道在百万级数据、内存有限的场景下选它是不是最优解。还有一个容易被忽略的点这套题的题量并不小时间却只给了一到两小时。很多人不是不会做而是被前面的客观题纠缠太久到编程题时只剩十几分钟。这也是我特别想强调的实习生笔试拼的不是算法天花板而是时间分配和稳定拿分的能力。1.2 从题型分布反推复习顺序客观题、简答题、编程题各有各的坑如果按“丢分惨烈程度”来给这三类题型排个序我的感受是多选题大于编程题编程题大于单选题。多选题的规则通常很残忍少选、多选、错选都不得分甚至有些平台是选错一个选项整题零分。这种规则逼着你在考场上有一种“克制感”不能像做单选题一样凭感觉猛选。我当时一个比较深的印象是简答题并不需要你写长篇大论它就是问你“如果要设计一个短链接系统你会分成哪几个模块”或者“线上服务出现CPU飙升你从哪些角度排查”。这类题目没有标准代码更像是在考察工程直觉。如果你只是埋头刷算法不接触真实项目到这种题目上会明显感觉到无话可说。编程题里的坑则体现在“看起来简单样例也过了一提交却超时”。原因无非是复杂度估错了或者没处理数据范围。2017年这套笔试题里编程题输入规模的上限写得比较夸张有些题故意放在最后就是考验你能不能快速判断出该用哪种算法。如果一上来就写递归大概率会在大数据量上爆栈。所以复习顺序上我建议这样安排先用两到三天把数据结构和操作系统的基础概念过一遍边看边配选择题练习把客观题的准确率提上去再花更多时间刷中等难度的算法题每道题都要做复杂度分析不能AC了就扔最后再去找一些开放性的设计题、场景题来练手提升自己用自然语言描述方案的能力。这个顺序比“一天刷十道难题”要稳得多。2. 客观题丢分重灾区基础概念越熟悉越容易错2.1 数据结构题会“用”不等于会“选”按我对这套笔试的印象数据结构相关的选择题很少直接问“栈的特点是什么”更多的做法是给你一个具体场景让你在几个结构之间做选择。这种题最容易翻车的地方在于每个选项单独看都有一点道理但你要选出的是“最优解”。比如有一类很典型的问题现在需要频繁按某个关键字查找记录数据总量会动态增长你会选择哪种存储结构选项里给出顺序表、二叉搜索树、哈希表、跳表。很多人看到“查找”就直接选哈希表却忽略了“动态增长”这个前置条件。如果数据量增长频繁哈希表可能面临多次扩容和rehash而跳表在插入和查找之间能保持一个更平稳的性能。这类题考的不是你会不会用哈希表而是你能不能把“最差情况”和“平均情况”分开考虑。还有一个高频方向是链表和数组的区别。笔试里会把它包装成“一段内存中需要频繁在头部插入和删除元素用哪种结构更好”。你要是只记得“链表插入删除快”就会漏掉一个前提题目可能在后面补了一句“内存空间要求尽量连续”那答案就要倾向数组加标记位或者用带空闲链表的数组。出题人不会无聊到故意难为你他是在模拟真实工程里的取舍。我在做这类题时的一个习惯是把题干里的每个限定词都圈出来比如“频繁”“平均”“最坏”“内存受限”“数据有序”。这几个词基本上决定了答案。如果你读完题只看到“查找”两个字后面的条件全被忽略那丢掉的分不冤枉。2.2 操作系统和网络经常以“二选一”形式出现操作系统部分线程和进程的区别、死锁产生的四个必要条件、虚拟内存和分页机制是固定考法。网络部分则集中在TCP三次握手、TIME_WAIT状态、HTTP和HTTPS的区别、DNS解析过程。这套笔试里有个很有意思的现象它不直接问“TCP和UDP有什么区别”而是给你一份聊天应用的描述让你判断为什么选择TCP而不是UDP。这种题大部分人都能答对真正的陷阱在后面一题它可能会反过来说“在线视频通话延时要低为什么可以用UDP”然后让多选里有“因为可以容忍少量丢包”和“因为不需要可靠传输”两个选项。猛一看都是对的但“不需要可靠传输”这个说法放到视频场景里就不严谨视频也需要可靠传输关键帧只是在实现上通过应用层做了容错而不是说可以完全不需要。复习这块内容的时候不要只背结论。我建议把每个协议或机制都问自己一层“为什么”。比如TCP为什么要三次握手而不是两次TIME_WAIT为什么要保留2MSL进程和线程切换各自的成本到底差在哪。这些“为什么”才是多选题里真正想考的东西。你背的结论只能应付单选多选一定会在细节上让你纠结。2.3 语言细节与数学逻辑题考场上的秒杀技巧这一部分我印象里包括不少C/C和Java的语言细节题。比如“下列哪种方式能正确创建线程”或者“Java中String、StringBuilder、StringBuffer在不同拼接场景下的效率”。这类题对项目经验少的人来说反而好拿分因为都是固定知识点只要背过就能答对。最容易丢分的是位运算相关的题比如“给定一个整数如何判断它是2的n次幂”。代码写法很简单一次n 0 (n (n - 1)) 0就能解决。但笔试不会让你写代码它把四个写法放在选项里每个看起来都很接近只有一个是兼顾“正数判断”和“位运算正确性”的。我当时就吃过亏以为n (n-1) 0就是全部忘了正数判断。这种题考得很细但也说明一个道理基础知识别停留在“我见过”要精确到“我能判断每一个边界”。数学与逻辑题通常出现在填空题或者单选的后半段比如条件概率、期望值、排列组合。这类题目的难度不高但计算量有一点。我的经验是遇到概率题不要急着列公式先在草稿纸上画一棵树或者列几个分支把每一种情况的概率标出来这样不容易漏。复杂排列组合题如果超过三分钟还没有清晰思路果断跳过去后面的编程题更值钱。3. 编程题从读题到AC三道典型题的完整推导过程3.1 字符串题把“反转/切割”类需求翻译成边界条件这套笔试的编程题第一题通常不会太难但题干会写得比较绕。常见的是字符串处理比如“给定一个字符串按单词为单位反转多余的空白字符需要去除每个单词之间保留一个空格”。这类题摆在第一题不是想卡人而是测试基本功和细心程度。我以这类题为例说一下做题时的拆解流程。第一步先把题目里的操作指令提取出来反转、按单词切分、去除多余空格。第二步明确边界条件字符串为空、字符串全是空格、单词之间有多个连续空格、字符串首尾有空格。第三步才开始写代码。很多同学的错误在于一上来就调用语言自带的split函数分割单词然后倒序遍历输出。这在大多数测试用例上没问题但遇到连续多个空格时某些语言的split行为会不一致容易在输出里多出空白字符串。更稳的做法是手动扫描字符串按“当前字符是否为空格”作为状态切换的条件把单词收集到一个列表里最后统一拼接。这样不管空格怎么变化结果都是可控的。我还记得当年笔试时这类题往往有个隐藏要求原始字符串可能长达10^6所以不能频繁做字符串拼接否则会产生大量临时对象导致超时。正确做法是使用可变字符数组或列表收集结果最后一次性转成字符串。这一步是“能过样例”和“能通过全部大数据用例”的区别。3.2 动态规划题状态定义决定你是否能在半小时内做对中等难度的编程题里动态规划几乎是必考。2017阿里这套题里有一道我印象比较深的三角形最短路径和要求从三角形顶部出发每次只能移动到下一层相邻的节点求到底部的最小路径和。题目本身不新但现场写的时候很多人会卡在状态定义上。我的建议是拿到动规题之后不要立刻写转移方程先用一个具体的小例子在纸上推演。比如三角形只有三层自顶向下走一遍把每一步的选择标出来。这样你会很快发现如果自顶向下递推需要额外处理边界节点而如果自底向上更新只需要在原数组上操作每一行都从下往上累加最终答案就落在数组第一个位置。更具体地说定义dp[i][j]表示从底部走到第i行第j列这个节点的最小路径和。那么转移方程就是dp[i][j] triangle[i][j] min(dp[i1][j], dp[i1][j1])。你不需要真的开一个二维数组可以在原始三角形数组上原地更新把空间复杂度降为O(1)。笔试环境里空间和时间一样重要能原地更新的地方尽量原地更新。动规题的另一个常见问题是初始化。很多人会把dp数组初始化成全0但有些题需要初始化为正无穷大才能让“不可达状态”不会被错误地参与比较。边界条件不是写代码的最后一步而是写代码前的第一步。建议以后拿到动规题强制自己先写注释状态含义、初始值、转移方向、答案位置。这四个注释写清楚了代码基本不会乱。3.3 图论题先估算复杂度再决定用哪种搜索图论在这套笔试里不一定会以标准的“给你一张图求最短路径”出现它可能包装成“有N个任务某些任务依赖另一些任务请给出一个可行的执行顺序”。这就是典型的拓扑排序。如果你对拓扑排序很熟那这道题是送分题无非就是统计入度、把入度为0的节点放入队列、依次处理。但如果你不熟现场硬推也能推出来只是会慢很多。这里我想分享一个“两分钟估算法”先看N的范围如果N是10^3级别那O(N^2)的朴素解法勉强能过如果N是10^5级别必须用O(NE)的算法。提到这是因为很多人在笔试时明明写出了思路正确的代码结果因为复杂度不达标只过了一部分测试用例。图论题尤其容易出现这种情况因为它本身就自带“遍历所有节点”的过程稍不注意就会多一层循环。另外搜索题里还有个隐藏考点递归深度。当N达到10^5时DFS递归很容易爆栈导致程序在接近答案前直接崩溃。如果你遇到一道需要遍历整棵树的题第一时间应该考虑用显式栈代替递归或者直接上BFS。我在当年笔试时就吃过递归爆栈的亏后来凡是看到“N最大可能超过10^5”的题默认不写递归。3.4 会写暴力解也是优势从60分到100分的过渡路径编程题不是只有AC和零分两种结果。很多在线笔试平台会按照通过测试用例的比例给分意思是你哪怕只能通过部分样例也能拿到一部分分数。所以我在笔试里一直坚持一个顺序先写一个确定正确的暴力解法把能拿的分数拿到手再思考怎么优化。举个例子如果题目要求“在一个长度为N的数组里找两个数使它们的和等于目标值”你可以先写双重循环暴力解这个版本在数据量小时一定能过。等他开始跑大数据用例的时候你再用哈希表优化成O(N)。这样做的好处是你永远不会因为某个优化没写完而落得一道题白卷。还有一个小技巧是编程题里如果题目明确说了“测试数据分为小规模和大规模”你可以针对小规模写暴力逻辑然后追加一段针对大规模数据的优化分支。这样的代码在工程里可能不太好看但在笔试抢分场景下非常实用。4. 在线笔试环境的隐性规则判题方式直接影响得分策略4.1 “本地能跑”和“平台通过”之间差了哪些细节很多同学在本地IDE里测试代码通过之后就直接复制到平台提交结果发现报了编译错误或者答案错误。这中间差的往往不是算法而是环境差异。首先是编译器版本。某些旧版本编译器不支持新的C11特性如果你在本地用了高版本的语法在平台上报错很正常。其次平台对输入输出的要求非常严格多一个空格、多一个换行都可能导致格式错误。更重要的是部分平台会用多个测试文件连续测试你的程序如果你的代码里包含system(pause)或类似阻塞语句第一个用例通过后程序就停住不往下走了。我在准备这套笔试的时候专门把所有代码都改成“标准输入流读完再输出”的模式并且不使用任何特定操作系统的命令。这个习惯一直保持到工作以后对线上判题系统来说非常友好。4.2 部分样例通过时如何精准定位边界问题提交之后返回“通过3/10个测试用例”是很常见的。这时候不要慌更不要反复提交看运气。正确做法是回头检查三个地方第一数据范围特别是数组索引是否可能越界第二是否考虑了空输入、单元素输入第三运算过程中是否可能发生整数溢出。我遇到过很多次代码逻辑完全正确只是把某个变量的类型定义成int而真实数据的乘积超过2^31-1导致溢出后结果变成负数。这类问题你自己在本地造数据基本察觉不到因为你会下意识地挑一些顺眼的输入。应对办法是提交前把所有可能参与乘法的变量都声明成long long。一次到位别省这个内存。另一个思路是看题目给的样例。样例往往是经过设计的它可能覆盖常规情况也可能暗示边界。如果样例能过但你不知道错在哪可以尝试构造几个极端情况数组全相同、字符串全是空格、数字为最大值。这些数据不需要提交你在本地跑一遍就能发现很多隐藏问题。4.3 代码风格和提交时机未必要“最后一个交卷”在线笔试里很多人习惯等到最后一分钟才交卷觉得这样能多检查几遍。但笔试平台往往会限制提交次数或者对每次提交都做全量测试频繁提交反而心理压力越来越大。更稳妥的做法是每道编程题写完后先做一次本地全量测试再一次性提交。代码风格在笔试中看似不重要其实影响你后续的查错速度。变量命名清晰、函数内部没有过长的嵌套能让你在回头debug时快速定位问题。我记得有一次考试编程题需要处理二维数组我第一次写的时候把行和列的变量名定义成了a和b写到后面完全忘了谁是谁浪费了十分钟才理清楚。从那以后我所有笔试代码都坚持用有意义的变量名哪怕多敲几个字母。还有一个值得注意的点不要在附加题上投入过长时间。附加题是拉分项不是必做项。如果你前面的基础题已经做完可以尝试一下如果编程题还没完全通过优先保证编程题的完整提交。5. 考场上真实的时间分配与心态管理经验5.1 需要优先保证的“基础分”把这套笔试题过一遍之后你会发现分值分布大概是这样的客观题占三到四成编程题占四到五成附加题占一到两成。如果你目标是拿到面试机会不需要追求附加题满分只要保证客观题的正确率和编程题前两题AC就已经具备很大优势。所以我建议做题顺序是先快速扫一遍所有题目标记出客观题里自己绝对有把握的题目优先做掉然后立刻进入编程题先把第一题写了回头再解决客观题里半会不会的题。不要从第一题按顺序一路做到底因为后面编程题带来的心理压力会影响你判断前面的选项。我当年就是这样操作的先把所有单选做完遇到多选犹豫的题先标记跳过然后做第一道编程题之后回来补多选最后再处理后两道编程题。这个顺序让我在时间上始终留有缓冲不会出现“编程题没时间写”的惨状。5.2 遇到不会的题先给自己的思考设置闹钟笔试过程中最怕的不是遇到不会的题而是卡在一道题上出不来。当时我做一道多选时觉得每个选项都有道理反复看了五分钟也没下定决心。结果等我一抬头时间已经过去二十分钟编程题还没来得及写。这个教训非常深刻。后来我给自己定了一条铁律任何一道客观题思考时间超过两分钟就标记跳过。编程题则分开对待如果读完题五分钟后还没有任何思路就先放下去做其他题等到最后再来攻。当你换了个思路再回头看往往能发现之前遗漏的突破口。在线笔试系统一般都有题号列表你可以通过标记功能把不确定的题跳过去最后统一处理。不要觉得跳过就是认输这是非常正常的应试策略。真正重要的是把整张试卷里那些“你本来就能拿分”的题全部拿到手。5.3 笔试结束不等于终结复盘与后续面试衔接笔试结束后哪怕你觉得发挥不理想也建议花半小时把题目大致回忆一遍。一方面是为之后的面试做知识准备因为面试官很可能会拿着你的笔试题目再追问一轮另一方面复盘能帮你发现自己知识体系的漏洞比盲目刷十道新题更有效。我当时在笔试结束后第一时间把每道题的考点记在备忘录里尤其是那些当场没做对的题。后来面试环节面试官真的问了一道和笔试差不多的字符串处理题因为我在笔试后专门整理过所以回答得特别顺。这个经验让我意识到笔试不只是“筛人工具”它同时也是一个很好的自学清单。另外笔试之后如果收到了面试邀约可以主动去了解自己笔试的失分点。很多公司的招聘系统会展示笔试报告或者你可以在面试时表达“我笔试阶段在XX方面准备得不够后来重新梳理了”。这会给面试官一种“这个同学在意每一次反馈”的印象在某些情况下比对答如流更加分。写在最后的个人经验经历过多次大厂笔试之后我的整体感受是实习生笔试出题并没有想象中那么“高不可攀”它更像是一场基础能力体检。题目设计者希望看到的是一个人在有限时间内能不能保持冷静、能不能分清主次、能不能把学过的知识稳定输出。这些都是工作中真正重要的能力。如果你正在准备类似的大厂实习笔试我的建议很直接先摸清试卷结构再分配复习时间客观题讲究准确率编程题讲究拿满基础分考场上遇到不会的题果断跳过最后再回攻。你不需要成为算法大神也能通过这类笔试但你需要成为一个“在考试环境下依然可靠”的人。希望这篇复盘能给你一些参考。祝笔试顺利。