猿辅导2019校招技术笔试题复盘:算法与计算机基础考点全解析 最近好几个读者私信问我想看看猿辅导2019校招技术类笔试题的考察方向和难度我一琢磨与其零散回复不如把当年那套题型的复盘和解析整理成一篇完整的博客。无论你是准备校招的应届生还是打算跳槽的社招选手只要目标是国内在线教育或者互联网中大型公司的技术岗这套笔试题背后的考察逻辑都值得仔细揣摩。猿辅导的笔试一向不是靠偏题怪题取胜而是非常看重基础算法的扎实程度、代码实现的规范性以及计算机基础知识的覆盖面这恰恰是很多人容易翻车的地方。这篇文章我会结合当时笔试的题型结构把客观题部分的核心考点、编程题部分的典型思路和代码实现都拆开揉碎地讲一遍。你不需要把它当成一套“过时真题”来刷而是当成一份“校招技术笔试的考察风向标”来用。我会尽量还原题目的考察意图并给出足够详细的解析和代码方便你照着练习和举一反三。1. 笔试整体结构与考察逻辑1.1 题型分布与时间压力2019年猿辅导校招技术类的笔试题型整体上分为两大块一块是客观题选择题为主另一块是编程题在线OJ形式。客观题覆盖了计算机网络、操作系统、数据库、编程语言基础、数据结构和算法理论题量大概在20到30道之间。编程题一般是2到3道难度阶梯式上升第一道偏基础最后一道有明显区分度。时间上给的并不宽裕我记得整套题的时间是90分钟左右。这意味着你不仅要会做还要做得快。客观题每道题平均只有两分钟左右的思考时间编程题需要在有限时间内完成读题、设计思路、编写代码、调试通过整个流程。很多人栽在时间分配上前面选择题纠结太久后面编程题没时间写或者编程题卡在边界条件上反复调试导致整场考试节奏全乱。所以你在准备这类笔试时第一件事不是刷难题而是训练“限时做题”的节奏感。我当时给自己定的策略是客观题每道题最多两分钟拿不准的先凭第一印象选一个并标记绝不恋战。编程题按照“先读题审清楚约束条件、再想思路、再写代码”的顺序来第一道简单题控制在15分钟以内留足时间给后面的压轴题。1.2 在线教育公司到底想考察什么猿辅导作为在线教育公司技术团队日常要处理的核心场景包括大规模直播课的稳定性、课件实时同步、题库系统的高并发访问、用户行为数据的收集与分析等。这些业务特点决定了笔试不会只考纯粹的算法题而是会兼顾计算机基础知识尤其是网络、操作系统、数据库这些在实际后端开发中高频使用的知识。举几个具体的例子直播课场景下客户端和服务端之间的数据通信依赖HTTP或者自定义协议所以TCP/UDP的区别、HTTP状态码的含义是选择题的常客。题库和用户系统依赖数据库所以SQL语法、索引失效的场景、事务的ACID特性也经常出现。高并发场景下进程和线程的区别、死锁产生的条件、锁的粒度选择都是操作系统部分的重点。说白了笔试不是为难你而是要通过一套题快速筛选出“基础扎实、能写代码、有计算机体系感”的候选人。你在复习的时候不能只抱着《算法导论》刷题还得把大学期间计算机基础课的核心概念过一遍尤其是那些能和实际业务场景挂钩的知识点。2. 客观题核心考点与避坑指南2.1 计算机网络别只背状态码要理解场景计算机网络是选择题的必考板块猿辅导考察的重点集中在TCP/IP协议族、HTTP协议、DNS解析流程这几个大方向。TCP三次握手和四次挥手几乎是必考题但考察方式往往不是让你默写流程而是给你一个具体的状态变化问你此时处于什么状态或者某个字段的值是多少。比如经典的考题“客户端发送完最后一个ACK后进入什么状态”答案显然是TIME_WAIT但很多人会记混成CLOSE_WAIT。这里有个小技巧TIME_WAIT是主动关闭连接的一方在收到对方FIN并发出ACK后进入的状态目的是保证最后的ACK能到达对方同时让旧连接的报文段在网络中消失而CLOSE_WAIT是被动关闭方收到FIN、还没调用close()时的状态。只要把“谁主动谁被动”这条主线抓住就不会混淆。HTTP状态码也喜欢考但题目不会直接问你“404什么意思”而是给你一个实际报错场景让你判断状态码。比如“服务器无法理解客户端的请求语法”对应的是400 Bad Request“请求的资源不存在”对应的是404“服务器内部错误”对应的是500。这些看起来简单但有几个容易翻车的地方301是永久重定向302是临时重定向307也是临时重定向但要求请求方法不变很多人会把302和307搞混。另外201是Created表示请求已经被处理并且创建了新资源和200 OK有细微差别。DNS解析流程也是高频考点考察方式通常是给你一个访问域名的过程问你正确的解析顺序。本地DNS缓存、hosts文件、本地DNS服务器、根域名服务器、顶级域名服务器、权威域名服务器这条链路要理清楚。我当时的记忆方法是先查自己缓存和hosts再问本地DNS本地DNS一步步迭代查询根、顶级、权威服务器。特别要注意的是本地DNS服务器查询过程中会使用递归查询还是迭代查询这个概念很多人会绕晕。2.2 操作系统死锁、进程调度和内存管理操作系统板块的考点相对固定但覆盖面挺广。死锁产生的四个必要条件互斥、持有并等待、不可剥夺、循环等待是选择题常客偶尔会换个问法比如“下列哪种策略可以破坏死锁的循环等待条件”答案是资源有序分配法。还要注意银行家算法这种避免死锁的策略虽然实现复杂但选择题基本停留在概念层面。进程和线程的区别、进程调度算法、虚拟内存和页面置换算法也是重点。调度算法里先来先服务FCFS、短作业优先SJF、时间片轮转RR、优先级调度这几个要对比着理解。高频考法是给一组进程的到达时间和执行时间让你算平均等待时间或平均周转时间。这类题没有捷径老老实实画甘特图就能算对但要小心短作业优先算法里的“抢占式最短剩余时间优先”变体稍微不注意就会算错。虚拟内存部分页面置换算法的考察频率很高。最佳置换算法OPT理想情况实际不可实现、先进先出FIFO、最近最久未使用LRU这三个是必须要掌握的。LRU的考点通常是给你一个页面访问序列和一个内存块数让你算缺页次数。这里有个实操心得LRU实现时除了理解思想还要知道在真实系统里可以用哈希链表来实现也就是HashMap双向链表这样能在O(1)时间内完成查找和更新。笔试虽然不要求你写代码但如果你在编程题里遇到LRU相关题目这个数据结构设计就是解题关键。2.3 数据库索引、事务与SQL优化数据库的考察集中在三块SQL语法、索引机制、事务特性。SQL语法不会考太复杂的多表关联但单表的增删改查、聚合函数、GROUP BY和HAVING的区别、ORDER BY的排序规则这些要非常熟练。索引部分是拉开差距的地方。比如“什么情况下索引会失效”答案是对索引列使用函数或表达式计算、隐式类型转换、LIKE以通配符开头、使用OR连接非索引列条件等。还有一个高频考法给你一个SQL语句问它能不能用到某个联合索引本质就是考最左前缀原则。记住一条主线联合索引(a,b,c)查询条件里只有包含a才能用到索引跳过了a直接用b或c索引就失效。事务的ACID特性以及隔离级别和并发问题脏读、不可重复读、幻读的对应关系也是选择题爱出的题。可重复读能避免脏读和不可重复读但在某些数据库默认隔离级别下仍可能出现幻读串行化最严格但性能损耗最大。这个知识点的记忆方法是画一张表横轴是四种隔离级别纵轴是三种并发问题把“能否发生”填进去一目了然。2.4 数据结构与算法理论时间复杂度不是背出来的客观题里还会有一部分纯粹的数据结构和算法理论题比如给一段代码问你时间复杂度、栈和队列的应用场景、哈希冲突的解决方法、二叉树的遍历序列推导等。二叉树遍历序列推导是每年都会出现的题型。题目通常给你前序遍历和中序遍历要你推出后序遍历或者给你层序遍历和另一种遍历要你还原二叉树结构。核心思路是前序遍历的第一个节点是根节点在中序遍历中找到这个根节点左边是左子树右边是右子树然后递归处理。操作熟练之后这类题基本30秒内能解出来。哈希冲突的解决方法开放定址法、链地址法、再哈希法等也喜欢考。链地址法是Java HashMap默认的冲突解决方式理解起来最直观开放定址法里线性探测和二次探测的区别要搞清楚尤其是查找时遇到空位置就停止这个特性这是判断元素是否存在的关键逻辑。3. 编程题实操解析与代码实现3.1 第一类必考题型双指针与滑动窗口近年在线笔试的编程题双指针和滑动窗口的出镜率非常高2019年猿辅导的题目也不例外。这类题目的特征是给定一个数组或字符串要求找出满足某种条件的子数组或子串比如“最长无重复字符的子串”“和为target的连续子数组”“盛最多水的容器”等。拿“最长无重复字符的子串”来说这是LeetCode第3题的原型。题目描述是给定一个字符串请你找出其中不含有重复字符的最长子串的长度。最直观的解法是暴力枚举所有子串再用一个Set判断是否有重复字符时间复杂度是O(n^2)在字符串长度稍大时就会超时。正确的做法是用滑动窗口加哈希表。右指针不断向右扩展把字符加入窗口如果发现当前字符已经在窗口中出现过就移动左指针直到窗口中不再包含这个重复字符。在移动过程中实时记录窗口的最大长度。下面给出C语言的实现版本这类笔试一般支持C/C/Java/Python但我更推荐用C或者Java来写因为Python虽然简洁但部分在线笔试平台对Python的输入输出处理有时会有坑#include string #include unordered_map #include algorithm using namespace std; class Solution { public: int lengthOfLongestSubstring(string s) { unordered_mapchar, int window; int left 0, right 0; int maxLen 0; while (right s.length()) { char c s[right]; window[c]; right; while (window[c] 1) { char d s[left]; window[d]--; left; } maxLen max(maxLen, right - left); } return maxLen; } };这里有一个非常容易踩的坑窗口收缩的条件是“当前字符在窗口中出现次数大于1”而不是“窗口左右指针之间的长度超过某个值”。很多初学者写成发现重复字符时直接把left跳到重复字符的下一个位置这个思路本身没问题但要确保窗口内其他字符的计数也同步更新正确。我建议统一用“右指针移动、维护计数、发现非法时左指针收缩”的模板虽然多几次循环但逻辑清晰不容易出错。3.2 第二类必考题型动态规划入门动态规划是校招笔试编程题的常客但2019年猿辅导的考察难度还不是特别高主要集中在经典模型背包问题、最长公共子序列、最长递增子序列、爬楼梯问题等。这类题目的特征是存在重叠子问题和最优子结构可以通过状态转移方程逐步推导出最终答案。拿“爬楼梯”问题举例你正在爬楼梯需要n阶才能到达楼顶每次你可以爬1阶或2阶问有多少种不同的方法可以爬到楼顶。这本质上是斐波那契数列的变种状态转移方程是dp[i] dp[i-1] dp[i-2]。笔试的时候很多人一看这个题很简单直接写递归int climbStairs(int n) { if (n 2) return n; return climbStairs(n - 1) climbStairs(n - 2); }这个提交上去大概率会超时因为递归会重复计算大量子问题。面试官想看到的不是“能跑出正确答案”而是“能分析出时间复杂度并做出优化”。所以正确的做法是动态规划自底向上计算int climbStairs(int n) { if (n 2) return n; int prev 1, curr 2; for (int i 3; i n; i) { int next prev curr; prev curr; curr next; } return curr; }时间复杂度O(n)空间复杂度O(1)。这个优化过程本身就是面试官考察的重点你有没有意识到递归的重复计算问题并能够用滚动数组优化空间。如果你在笔试的代码注释里简单写一句“使用滚动数组优化空间”会是个不错的加分项。动态规划题目在笔试里不会只考这么简单的往往会在经典模型上包装一层“实际业务场景”。比如把爬楼梯包装成“课程学习顺序安排”把背包问题包装成“资源分配问题”。面对这类题核心能力是识别出它底层到底是哪个经典模型然后套用相应的状态转移思路。这个识别能力只能靠多刷题来培养没有捷径。3.3 第三类压轴题型复杂数据结构与综合应用压轴题一般会结合多种数据结构或算法技巧常见组合有“二叉树递归动态规划”“数组哈希表排序二分查找”。我记得有一个高频题大致的考点是把二叉搜索树转换成累加树给定一棵二叉搜索树把每个节点的值替换成大于或等于该节点值的所有节点值之和。这类题的难点不在于数据结构的操作有多复杂而在于你能不能发现问题的本质。拿这个题来说二叉搜索树有一个重要性质中序遍历得到的是有序递增序列。题目要求将每个节点的值换成所有大于等于它的节点值之和那么反中序遍历先访问右子树、再访问根节点、最后访问左子树得到的就是递减序列。遍历时用一个累加变量记录已经访问过的节点值之和每访问到一个节点就把它加上这个累加变量并更新累加变量。struct TreeNode { int val; TreeNode *left; TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) {} }; class Solution { public: int sum 0; TreeNode* convertBST(TreeNode* root) { if (root NULL) return NULL; convertBST(root-right); sum root-val; root-val sum; convertBST(root-left); return root; } };这个代码只有短短十几行但包含了几个重要的考察点第一你是否知道二叉搜索树的遍历性质第二你是否能想到反中序遍历这个切入点第三全局变量在递归中的使用是否熟练。很多人卡在第一点只想着怎么暴力计算每个节点的所有大于等于它的节点和时间复杂度直接变成O(n^2)在数据量稍大时就会超时。对于压轴题我有一条实战经验如果10分钟内没有清晰的解题思路不要死磕先把暴力解写出来提交拿到部分分数然后逐步优化。在线笔试的判题系统一般会返回部分通过的数据暴力解至少能拿一些分值。等搞定其他题目后如果还有时间再回头优化。这个策略听起来不够“硬核”但非常实用。4. 输入输出处理与提交细节4.1 牛客网风格的输入输出陷阱2019年猿辅导技术岗笔试题是在牛客网平台上完成的这里的输入输出处理和LeetCode的“函数完成填空”模式完全不同。牛客网的题目需要你自己写完整的main函数自己读取标准输入自己打印输出。这个差异让很多习惯刷LeetCode的同学栽了跟头。最常见的输入格式是第一行一个整数n表示后面有n行数据每行包含若干个空格分隔的整数。比如一个典型的题目“第一行输入一个整数n第二行输入n个整数求这n个数的和”。C的标准解法是#include iostream using namespace std; int main() { int n; while (cin n) { long long sum 0; int val; for (int i 0; i n; i) { cin val; sum val; } cout sum endl; } return 0; }注意这里用了while (cin n)循环读取而不是只处理一组数据。牛客网笔试的测试数据常常包含多组测试用例你不能假设只有一组输入。如果只写一次处理逻辑往往只能通过部分测试用例。还有一个坑是数据范围。题目描述里如果看到“n小于等于10的9次方”“数组元素大小在10的9次方量级”求和结果很可能超过int的范围要用long long。我见过太多人算法思路完全正确就因为int溢出导致答案错误。4.2 自测边界条件笔试题的隐形扣分点编程题提交后系统会跑多组测试数据其中大部分数据是正常的但一定会夹杂几组边界数据用来测试你的代码鲁棒性。最常见的边界条件包括空数组、只有一个元素的数组、元素全是相同值、递增序列、递减序列、最大值和最小值。这里分享一个自查清单每次写完代码后照着清单过一遍如果输入是数组或字符串检查长度为0或长度为1时是否正常工作如果题目涉及排序检查完全有序和完全逆序的情况如果涉及数值运算检查是否可能溢出int范围如果涉及索引访问检查是否存在数组越界风险如果涉及循环退出条件检查是否可能出现死循环以“找出数组中第二大的数”为例很多人写的代码能通过正常数据但遇到[1, 1, 1]这种数组就崩了因为第二大的数不存在代码可能返回一个未初始化的值。这类边界问题如果不在编码时考虑周全提交后就会出现“答案错误”的判定结果而且你不会知道错在哪组数据上。自我检查时可以在本地IDE里手动构造几组边界数据运行一遍而不是只跑题目给的示例。这个习惯在笔试时特别管用因为大部分在线判题系统不会告诉你具体错在哪组数据你只能靠经验提前排查。5. 备战路径与时间分配方案5.1 从真题倒推复习优先级如果你现在距离笔试还有三到四周复习节奏可以这样安排第一周围绕数据结构与算法的基础题型展开数组、链表、栈、队列、哈希表、二叉树这些基础数据结构要全部过一遍确保相关操作能手写实现。第二周专项练习动态规划和贪心算法这是笔试的区分度所在。第三周集中刷计算机基础知识的客观题网络、操作系统、数据库三块按比例分配时间每天刷50道以上。第四周进入模拟笔试阶段用牛客网或者LeetCode的模拟考试功能严格按90分钟限时完成整套题目。如果你只有一周时间策略就要更激进优先保证编程题的第一题能稳定AC因为第一题通常是数组或字符串相关的简单题出题风格相对固定。客观题部分优先复习计算机网络和数据库这两个板块短时间内记忆效果最好。操作系统里死锁、进程调度、页面置换三个考点性价比最高投入少量时间就能拿到分数。至于难度较大的动态规划压轴题如果没时间系统刷题至少把背包问题、最长公共子序列、爬楼梯这几个经典模型的模板代码背下来考试时如果遇到类似的题目可以套用模板拿部分分数。5.2 刷题平台与学习方法建议我当时主要是用LeetCode和牛客网两个平台配合着来。LeetCode题目质量高分类清晰适合按知识点专项突破。牛客网则更适合模拟笔试环境因为它的在线编辑器、输入输出处理方式、判题机制都和真实校招笔试一致用牛客网刷题可以提前适应考试节奏。具体的学习方法上我强烈建议“分类刷题而不是随机刷题”。LeetCode的题库可以按标签筛选比如先集中刷一周“数组”类题目再刷“动态规划”类题目这样能快速掌握同一类题目的出题规律和解法套路。如果随机刷题今天做一道链表明天做一道图论知识点之间没有形成体系进步会非常缓慢。另外一个容易忽略的学习方法是做完每道题后一定要看题解尤其是看评论区或者官方解答里的多种解法。同一个问题往往有暴力解、优化解、最优解对比分析每一种解法的思路和复杂度能够帮你建立“由浅入深”的解题思维。笔试时你就不会满足于“能通过”而是会主动思考“有没有更好的做法”这种思维在面试环节也非常加分。5.3 盘点笔试当天的应试策略笔试当天时间管理比任何一题都对总成绩影响更大。我的建议是拿到试卷后先花两分钟快速浏览整套题对编程题的难度有个预判。然后先做客观题遇到拿不准的题目不要死磕先行标记等做完编程题后再回来检查。客观题和编程题的分值通常是50比50如果因为客观题上的过度纠结导致编程题没写完损失会非常大。编程题部分的做题顺序是先做最简单的第一题确保AC后再做第二题最后才是压轴题。压轴题如果实在没有思路可以先写一个能通过部分数据的暴力解法这样至少能拿到一些分数。记住笔试的目标是总分最大化不是每题都最优解合理放弃部分难度是明智的选择。提交代码前留出三分钟检查是否有多余的调试输出变量是否都初始化了输入读取是否正确输出格式是否和题目要求一致这几个小细节往往是决定能否从“部分通过”变成“全部通过”的关键。6. 复盘总结与个人经验分享整套猿辅导2019校招技术类笔试题做下来我最大的感受是它不是一个只靠刷题就能应付的考试而是对“算法基本功、编码能力、基础知识体系、应试策略”四方面能力的综合考察。算法题占大头但并非全部客观题的分量同样不容忽视只有两手抓、两手都要硬才能在笔试中稳定发挥。我自己在校招季实际准备过程中踩过两个比较深的坑分享出来希望你能避开。第一个坑是前期只刷LeetCode完全不看计算机网络、操作系统和数据库的选择题结果第一次模拟笔试客观题的正确率不到60%许多基础知识都在“好像学过但记不清”的状态。后来我调整了复习计划每天晚上固定抽出半小时刷牛客网的基础知识选择题坚持一周后正确率明显提升。第二个坑是写代码时只追求逻辑正确忽略了输入输出处理和边界条件导致明明算法思路正确却在判题时因为读取问题或溢出问题得分很低。这个坑只能靠多做牛客网风格的题目来填平。如果你也想冲击猿辅导或者其他在线教育公司的技术岗我建议目标定得高一点但准备要踏踏实实。每天保持至少三道算法题的刷题量坚持一个月笔试通过的把握就会大很多。对于那些错题不要只看一遍答案就略过一定要自己在编辑器里重新默写一遍完整的代码确保真正掌握了思路而不是眼熟。最后再分享一个小技巧笔试前三天不要再挑战新题难题而是把之前做过的错题和经典题目重新看一遍尤其是那些思路已经掌握的题目快速过一遍代码保持手感。这段时间的心态调整比知识吸收更重要紧张状态下反而容易把本来会做的题做错。带着“我已经准备好了”的自信走进考场把这套题当作一次普通的练习你就已经超过了一半的竞争者。