猿辅导校招笔试复盘:算法题与系统设计全解析

发布时间:2026/8/29 1:41:59
猿辅导校招笔试复盘:算法题与系统设计全解析 我一直觉得校招笔试是一个很奇妙的筛选机制。你刷了三个月题以为自己准备得够充分了结果打开猿辅导2023校园招聘技术岗笔试三这套卷子还是会发现有些题让你卡了十来分钟。作为参加过2023届校招、并且在在线教育领域做过一段时间开发的过来人我今天把当时做这套题的完整复盘整理出来包括题型结构、算法题的推导过程、场景题的答题套路以及我后来对比其他同学踩坑记录后归纳出的高频失分点。这篇文章适合三类人看正在投猿辅导或同类在线教育公司技术岗的应届生想做校招真题复盘但找不到完整解析的求职者以及想了解在线教育行业技术笔试到底在考什么的非应届开发者。我会尽量把每一道题的思路讲透而不只是贴个答案。1. 拿到这套题的第一印象题型分布与现场节奏1.1 一套典型的三段式试卷结构说句实在话猿辅导这套第三场笔试和我提前刷过的前两套题有一个很明显的不同——它把算法题的难度梯度拉得更开了。如果你是按前面简单、后面困难的心态去做的很容易在第一道编程题上就浪费过多时间。整套卷子从结构上看基本是三个板块选择题、编程题、场景设计/简答题。我按考场上大概的分值配比做了一个还原方便你感受侧重点板块预估题量预估分值占比考察重心基础选择题8-10题30%操作系统、计算机网络、数据库、编程语言基础编程题2-3题50%数据结构与算法、代码实现能力场景设计/简答题1-2题20%业务理解、系统设计、逻辑表达为什么把编程题分值压得这么高因为在线教育公司对技术岗的诉求非常直接你要能在高并发场景下写出稳定高效的代码。用户的访问行为是有明显高峰期的比如晚间直播课集中开课时一瞬间的流量可能比白天高几十倍。笔试不看你背了多少八股而看你能不能动手解决实际问题。1.2 平台操作与赛制细节这套题用的是牛客网系统核心代码模式不需要自己处理输入输出。但这里有个细节很多人会翻车核心代码模式意味着你的代码会被塞进一个预定义好的类或者函数里函数名和参数类型必须严格匹配多一个空格、少一个引用符号都可能导致编译失败。我当时的选择是先用本地IDE调试关键算法题的边界用例再把完整代码贴回去。这样做的好处是本地有断言和打印调试速度快坏处是时间紧张时容易两头顾不上。后来我总结了一个更稳妥的做法——如果某道题你已经完全确定思路直接在网页编辑器里写写完用系统给的测试用例跑一遍不要来回切窗口省下的时间足够你做完整道场景题。另外一个容易忽视的点系统支持的语言里C、Java、Python 的编译标准不太一样。我当时选的C但发现题目模板里给的类名是Solution方法名是solve这类约定俗成的命名你不需要额外去继承什么只要按模板补全方法体。如果平时习惯用Python刷题建议笔试前先看一眼牛客网上的C模板长什么样万一现场想换语言也不至于懵。2. 编程题复盘三道真题向的完整推导编程题是这套卷子的重头戏。为了不影响未来批次笔试的公平性下面我不直接贴原题面而是用三道考察方向完全一致的变形题来做推演。每道题我都会从题目抽象、思路演进、复杂度分析到最终代码走一遍还原我当时在考场上的思考链路。2.1 拓扑排序课程依赖关系检测第一道编程题经典的课程依赖判断。题目大意是系统里有n个课程模块部分模块必须修完前置模块才能解锁。给定一组依赖关系判断学员能否完成所有模块如果能输出一种学习顺序。这几乎是图论里拓扑排序的标准模板题。为什么在线教育公司爱出这个因为先修课-进阶课的结构就是一张有向无环图直播课、录播课、练习册的解锁逻辑都依赖这个模型。题目本身不难但考了一个很实用的点你能不能把业务场景抽象成图模型。解题思路分两步。第一步把每个课程模块看作图的顶点依赖关系看作有向边[前置模块 - 当前模块]。第二步借助队列做Kahn算法的BFS拓扑排序。核心在于维护每个节点的入度表每处理完一个节点就把它的后继节点入度减一减到0就入队。当时我写的C代码长这样#include bits/stdc.h using namespace std; // n: 课程数量, prerequisites: 依赖关系集合 {前置课, 当前课} vectorint findOrder(int n, vectorvectorint prerequisites) { vectorint indeg(n, 0); vectorvectorint g(n); for (auto e : prerequisites) { g[e[1]].push_back(e[0]); indeg[e[0]]; } queueint q; for (int i 0; i n; i) { if (indeg[i] 0) q.push(i); } vectorint ans; while (!q.empty()) { int u q.front(); q.pop(); ans.push_back(u); for (int v : g[u]) { if (--indeg[v] 0) q.push(v); } } return ans.size() n ? ans : vectorint(); }注意一个细节我用ans.size() n来判断是否存在拓扑序。如果存在环路比如课程A依赖B、B又依赖A那么两个节点的入度永远不可能同时变成0最终入队的节点数一定小于n这时候应该返回空数组。这个判断比设一个visited计数器更干净也少写一行代码。复杂度上时间O(n m)空间O(n m)m是依赖关系的数量。这道题真正想拉开差距的不是能不能AC而是你在环的判断上是否严谨。很多人AC了前面的大部分用例唯独测到环形依赖时超时或者返回了错误顺序就是吃了这个亏。2.2 贪心排序不重叠课程区间第二道编程题一上来就带着明显的业务色彩。题目大意是一个辅导老师在某天可能会被分配若干个课程片段每个片段有开始时间和结束时间老师同一时间只能上一个班问最多能安排多少节课不冲突。这就是经典的无重叠区间变体思路是贪心。贪心策略的关键在于按结束时间从小到大排序然后依次选择那些开始时间不早于上一个选中片段结束时间的片段。为什么按结束时间排序而不是按开始时间因为结束早的片段会给后面的选择留出更多空间。这个道理听起来简单但很多人在考场上一紧张就开始想动态规划白白浪费了时间。代码实现如下int maxLessons(vectorpairint,int intervals) { if (intervals.empty()) return 0; sort(intervals.begin(), intervals.end(), [](auto a, auto b) { return a.second b.second; // 按结束时间升序 }); int cnt 1; int lastEnd intervals[0].second; for (int i 1; i intervals.size(); i) { if (intervals[i].first lastEnd) { cnt; lastEnd intervals[i].second; } } return cnt; }这个解法的时间复杂度是O(n log n)主要是排序的消耗空间复杂度O(1)。如果题目放宽到带权重的版本比如每节课的收益不同那就必须上动态规划了但笔试这道题只要求最多能安排多少节所以贪心就是最优解。我在这里想多说一句审题一定要慢。我当时看到一个细节——题目里给的区间是左闭右开还是左闭右闭直接影响边界判断。如果是左闭右开那么[9, 10)和[10, 11)是不冲突的如果是左闭右闭[9, 10]和[10, 11]在10点整就冲突了。这套题用的是左闭右开所以代码里判断条件写是对的。这种题目里一句话的差异就是决定你和小部分高分选手差距的地方。2.3 背包变体优惠券凑单问题第三道编程题我记得更清楚因为它非常有行业特色。大概意思是用户下单后有一批优惠券每张券有固定面额每笔订单最多可以用若干张问如何凑出一个最接近订单金额且不超过订单金额的抵扣总价。这道题本质上是一个01背包问题。目标金额当背包容量每张券的面额当物品重量和价值这里价值和重量一样能凑出的最大不超过目标值的金额就是答案。只不过它不是问能不能正好凑出而是问最接近目标值的组合是多少。01背包一维数组优化的代码比较短int bestDiscount(vectorint coupons, int target) { vectorbool dp(target 1, false); dp[0] true; // 面额为0一定凑得出 for (int c : coupons) { for (int j target; j c; --j) { dp[j] dp[j] || dp[j - c]; } } for (int j target; j 0; --j) { if (dp[j]) return j; } return 0; }这里用vectorbool而不是vectorint因为每个状态只关心能不能凑出不需要记录具体方案。内层循环必须从target倒序遍历到c这样每张券只会被使用一次。如果正序循环一张券就可能被重复使用——那变成完全背包了答案就会错。我在考场上第一次提交时并没有直接过因为我忘了处理优惠券面额比目标金额还大的情况。内层循环j c的判断天然跳过了这种情况但外层判断我写成了if (j c dp[j - c])逻辑上没问题不过没有dp[j] dp[j] || ...这种写法简洁。这个优化看着小但对时间紧张的笔试来说能少写一行是一行。3. 简答与场景题的拿分逻辑3.1 这类开放题怎么答才不丢分这套卷子的最后有一道场景设计题也是我见过很多人直接空着不写、却分值不小的题。题目大意是在线上课堂场景里一个老师要给几千名学生同时上课涉及音视频和消息互动请你从技术角度谈谈如何保证消息的实时性和可靠性。这类题没有标准答案但阅卷时有一个比较明确的给分维度你能不能把模糊的大问题拆成清晰的子问题并且每个子问题给出合理的选型。空着不写肯定0分写一堆用Redis、用MQ这种名词堆砌也拿不到高分。我的答题框架通常是四步走问题拆解把消息实时性拆成上行链路学生端发消息到服务端和下行链路服务端推送消息到所有学生端。量化约束估算单直播间在线人数、消息频率、可容忍的延迟上限。比如假设5000人在线点赞消息允许秒级延迟弹幕互动允许500ms以内连麦信令要求100ms以内。给出架构选型上行用HTTP短轮询不现实WebSocket长连接是主流下行可用消息队列削峰填谷再用网关做扇出。指出权衡如果要保证不丢消息可以用ACK重传机制如果追求极致实时性可以牺牲一点可靠性采用最多一次投递。最后一步特别关键因为阅卷人想看到你有没有工程判断力而不是只会背方案。3.2 举个例子模拟一场万人直播间的方案设计我当时在考卷上写了一个简化的分层方案。客户端通过WebSocket与接入网关维持长连接网关负责鉴权和连接管理。学生发送的互动消息先进入Kafka这类消息队列做缓冲再由推送服务消费并批量推送到直播间内的所有连接。批量推送的设计是为了避免一条消息触发几千次独立的网络IO。为什么用消息队列而不用业务进程直接推因为直播间的流量有明显的脉冲特征开播瞬间可能涌入大量用户和消息直接推送容易把服务打挂。消息队列能把峰值流量先存下来让下游按自己的消费能力慢慢推这就是削峰填谷。至于实时性Kafka的消费延迟在毫秒到几十毫秒级别完全够用。我还在答卷里提到了失败补偿机制如果某个学生端的WebSocket断开客户端需要自动重连重连成功后服务端根据消息序号做增量补发。这道题我最后估分不低主要原因就是有拆解、有选型、有取舍不是一个空泛的架构图。4. 从题目反推出题人在筛选哪四种能力笔试结束后的第二天我对照这套题做了一个反推如果我是出题人我到底在筛选什么样的人想明白这一点下次遇到类似题目时就不容易慌。4.1 基础功扎实度选择题里出现操作系统进程调度、TCP三次握手状态、数据库索引失效场景、HashMap扩容机制这类题其实都是在考察计算机基础是否牢固。这些东西平时写业务代码不一定用得到但一旦遇到线上问题能不能快速定位往往取决于基础功。在线教育公司的业务链路特别长——从客户端到网关到业务服务到数据库再到对象存储任何一个环节出问题没有基本功的人只能干瞪眼。4.2 问题抽象能力把课程依赖抽象成有向图、把优惠券凑单抽象成背包问题这就是问题抽象能力。笔试不考你在真实业务里从零到一的建模过程而是考你看到一个描述性题目后能不能快速提取出关键逻辑结构。我建议平时刷题时不要只看题解而是强迫自己先圈出题目里的名词和关系想清楚这个场景的本质是什么再动手写代码。4.3 工程落地意识场景设计题在这一项上做了重点考察。能画出漂亮的架构图不算本事能在图里标出瓶颈、能说出每个组件出故障时会怎样才算有工程落地意识。几百人在线的小班课和几万人在线的大直播课系统设计完全不一样不考虑量级直接套模板是最典型的扣分项。4.4 表达与取舍能力这听起来和写代码关系不大但校招进来的人终究要参与团队协作。代码写得好不好是一回事能不能把自己的思路讲清楚、能不能在方案冲突时做出合理取舍是另一回事。所以场景题的答题过程其实也是一次表达能力测试。哪怕你最后的方案不是最优只要逻辑链条完整分数往往不会低。5. 复盘之后整理的高频失分细节我后来和几个一起做题的同学对过反馈发现大家失分的点高度集中。整理成清单希望能帮你避开这些坑。5.1 编程语言层面的失误C的unordered_map头文件没写全、Java的HashMap忘记导入、Python的缩进在粘代码时被自动替换成了空格——这些问题在本地IDE里根本不会出现但提交后就是编译不过。比较土的办法是笔试前两周养成在网页编辑器里直接写代码的习惯至少每周完整提交一次提前适应没有本地报错提示的环境。另外用C刷题时有些人习惯把#include bits/stdc.h写在最前面这个在牛客网是可以用的但在某些严格环境可能不行。稳妥起见看清题目给出的模板里有没有这个头文件有就放心用没有就老老实实列vector、queue、algorithm这些具体头文件。5.2 算法思路没问题但细节翻车没开long long区间求和、乘法结果可能超出int范围。特别是背包类题目里金额累加溢出之后会得到完全错误的答案。递归爆栈树或图遍历用DFS递归写法一旦数据量到十万级别本地跑可能没事OJ上直接栈溢出。解决办法是改用显式栈或BFS。全局变量没有重置有的题目需要你实现一个类的方法如果类里有静态变量或者全局变量记录状态运行多个测试用例时这些变量不会自动清空结果第二个用例必错。笔试前可以养成一个习惯所有中间状态都定义在方法内部。5.3 时间分配和考试策略上的问题我看到很多人死在第一道编程题上——不是不会做而是非要写一个最优解结果浪费了40分钟。校招笔试不是竞赛满分不是目标在有限时间内拿尽可能多的分才是目标。我的策略是拿到卷子先用5分钟通读全部题目按能AC的题、能拿部分分的题、完全没思路的题分三个优先级。对于实在没思路的题写一个暴力解或者干脆把思路以注释形式写上去让阅卷人知道你是理解题意的至少能拿过程分。选择题上同样有策略。有些题的选项是明显错的比如MySQL的隔离级别和幻读对应关系记反了这类基础题不该丢分。如果遇到不熟悉的知识点先跳过做完编程题再回来蒙千万别在一道选择上卡10分钟。6. 按这套题反推的复习优先级如果你现在才开始准备或者做了这套题以后发现很多地方不熟我给你一套按优先级排的复习路径。6.1 数据结构优先级排序先抓住最核心的几类数组/链表/栈/队列、哈希表、树二叉树、二叉搜索树、堆、图邻接表、拓扑排序、最短路。这四个方向覆盖了笔试里八成以上的编程题。再往下的并查集、线段树、Trie树属于进阶内容时间充裕可以补不充裕先放一放。在线教育行业比较偏爱和关系状态流转有关的数据结构所以图相关的题出现频率比普通互联网公司更高尤其值得多花时间。6.2 算法专题优先级排序排序和二分是基础中的基础。然后是双指针和滑动窗口这类题代码量小、思路变化多性价比极高。接着是BFS/DFS、贪心和动态规划。动态规划不用追求偏难怪题把背包、最长公共子序列、打家劫舍这一类的经典模型吃透就够了。我建议按专题刷而不是按题目序号刷。因为哈希表相关题刷10道和刷20道可能只是数量的差别但贪心相关题刷10道你基本就能总结出什么时候该按结束时间排序、什么时候该按差值排序这类判断。刷题过程中准备一个错题文档把每道题的错误原因分成思路错、边界错、语法错三类考前只看这个文档比重新刷一遍题效率高得多。6.3 非算法部分的复习策略选择题涉及的计算机基础优先级是计算机网络 操作系统 数据库 编程语言底层。网络方面TCP握手挥手、HTTP状态码、HTTPS握手过程几乎是必考的操作系统重点看进程与线程、死锁、内存管理数据库重点看索引、事务隔离级别、SQL执行顺序。场景题不用刻意背答案但至少要吃透两个经典案例一个是消息推送系统适合在线课堂、弹幕、IM一个是直播/点播系统的架构。把这两个案例的架构图画熟练面试或者笔试遇到类似问题时你就有了一套可复用的基础模板。最后分享一个我在后续几场笔试里反复验证的经验做完题千万别急着交卷哪怕只剩十分钟也要回头检查一遍每道题的时间复杂度和空间复杂度有没有写清楚。有些多选或简答题阅卷人真的会因为你标注了复杂度而多给一分。毕竟校招季机会就那么几次多一分就可能让排名前进一截。