尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

猿辅导2017校招笔试题复盘:从二叉树遍历到拓扑排序的实战解析

猿辅导2017校招笔试题复盘:从二叉树遍历到拓扑排序的实战解析 整理旧电脑时翻出一份命名规规矩矩的文件“猿辅导2017校招笔试题卷一”。点开之后愣了很久那年秋招的许多细节一下子都冒出来了——在牛客网上等开考进入考试房间时的心跳还有交卷时的那一身冷汗。这篇文章不整理标准答案也不是把原题抄一遍而是从“参加过这场笔试的求职者”和“后来也接触过校招命题的从业者”两个角度复盘这套卷子给我的体感以及它背后真正想筛选的东西。准备投在线教育类公司技术岗的同学或者想对比2017年前后校招笔试题型差异的朋友都可以挑自己需要的部分看。我拿到的试卷线上作答满分100分总时长120分钟题型分单选、多选和编程题三块。这个结构放在2017年并不稀奇但如果你把当年各家的出题风格横向比一圈会发现猿辅导这套题出得很克制没有偏题怪题没有那种靠死记硬背才能答对的选择题整体难度曲线平滑策略是“基础理论选人编程题分层”。换句话说选择题保证每个人都能动笔编程题才是真正拉开差距的地方。1. 拿到卷子的前十分钟先看布局再动笔很多人的习惯是从第一题顺序做到最后一题但我打开试卷后的第一件事不是抢着做题而是花三五分钟把整张卷子的题型分布、分值权重和编程题难度大致过了一遍。这套题的结构大概是下面这个感觉题型题量分值占比我的时间预算单选题15题30分30分钟多选题5题15分15分钟编程题3题55分70分钟最后检查——5分钟这个时间预算不是乱拍的。单选涉及知识面广但每道题本身不深30分钟足够多选少选错选都不得分需要更谨慎但题量少最关键的是编程题占55分而且在线判题环境里调试一次可能要来回几分钟必须保证足够的整块时间。我当时的判断是如果前面选择题卡住超过两分钟立刻在草稿纸上标记出来先选一个最可能的答案后面有空再回来看绝不在单选题上赌命。这个策略在编程题量大的卷子里尤其重要因为一旦编程题时间被吃掉后面会非常被动。另外一个小细节开考前值得先切到编译器界面新建一个文件随便跑一个System.out.println(hello)或者print(11)确认环境能正常编译运行。这一行测试代码能避免一种很尴尬的情况——题做完了最后因为本地环境配置问题浪费十分钟。在线考试平台偶尔会有输入法冲突、IDE启动慢之类的问题提前花一分钟检查比考到一半再折腾舒服得多。2. 选择题里的硬核考点基础理论中那些容易卡壳的细节这套卷子的选择题记忆比较深的是三类二叉树遍历、网络状态机、语言基础细节。题目本身不算难但考得很“活”需要现场推导而不是单纯背结论。2.1 二叉树遍历光背模板真的不够有一道题大概是给出一棵二叉树的前序遍历序列ABDCEGF和中序遍历序列DBAEGCF问后序遍历结果。这类题在网上刷题平台见过无数次但考场上还是有相当一批人会慌因为平时都靠“根据序列直接套口诀”没有养成重构树的习惯。我的做法是老老实实画图。前序的第一个结点一定是根所以根是A再看中序A左边是DB、右边是EGCF说明左子树有两个结点、右子树有四个结点。回到前序去掉A之后前序序列是BDCEGF那么B一定是左子树的根。再看中序左子树部分DBD在B左边所以D是B的左孩子。右子树同理前序中C在剩余结点的最前面C是右子树的根中序EGCF中C左边是EG、右边是F所以F是C的右孩子。继续推导可以恢复出整棵树。一旦树的结构画出来后序遍历就是顺手的事先左后右再根结果是DBGEFCA。这个推演过程在考场上看起来花时间但它比记忆口诀可靠得多而且如果题目改成“根据遍历结果还原二叉树”或者“判断哪个遍历序列不可能是某棵树”画图法一样适用。2.2 网络与操作系统别和概念混脸熟多选题部分有关于TCP连接状态的题。这种题最坑的地方在于你背过SYN_SENT、ESTABLISHED、FIN_WAIT_1这些状态还远远不够它要你判断在某个事件发生后状态会跳到哪一步。比如主动关闭连接的一方发送FIN之后进入什么状态收到ACK之后又进入什么状态如果把FIN_WAIT_1和CLOSE_WAIT搞混基本就废了。应对这类题我在复习时就给自己定了一个规矩不背孤立的状态名而是把整个状态变迁画成一条线。实际做题时遇到拿不准的就在草稿纸上把顺序写出来模拟一次完整的连接建立和释放过程比凭感觉选要稳得多。操作系统部分有和死锁条件相关的多选题。这里出题人喜欢挖的坑是“条件描述得很像但少了一个关键限定”。比如互斥条件、请求与保持条件、不可剥夺条件、循环等待条件四个都满足才是死锁的必要条件。选项里如果把某个条件改成“资源可以剥夺”这个选项一定是干扰项。做题时看清楚每个选项的主语和限定词比记住定义本身更重要。2.3 语言基础C、Java和Python的细节差异语言类选择题在这套卷子里占比不小而且倾向于考“两种语言对应概念的区别”。比如Java的重写和重载、C虚函数表、Python中列表*运算的坑都会出现。这些内容单独拿出来都不难混在一起考容易让人产生一个错觉——觉得选项差不多都对。实际上出题人故意把不同语言的规则放在相似的结构里检验你是否真的理解而不是一知半解。我的建议是复习语言基础时不要只看主语言的语法花一点时间横向对比。比如C的const和Java的finalPython的浅拷贝和C的深拷贝C虚继承和Java接口默认方法。笔试很可能不会直接考这种宏观对比但理解差异之后做那些细节题的正确率会明显提高。3. 三道编程题的完整复盘从审题卡壳到一步步AC编程题是这套卷子最核心的部分一共三道覆盖了字符串处理、动态规划/贪心、图论拓扑。分开回顾一下我答题时的思路和卡壳点。3.1 第一道编程题字符串统计与自定义排序这道题的场景是教育系统里的作业文本处理给出一行由小写字母组成的字符串统计每个字母出现的次数按出现次数从大到小输出次数不为零的字母如果出现次数相同按字母的ASCII码升序输出。第一反应是直接用哈希表统计然后按(出现次数, 字母顺序)排序。常规思路能做但我当时差点在“比较器”上翻车。如果用的是Java需要写compare时注意返回值是正负不是布尔如果用Python可以用sorted(dict.items(), keylambda x: (-x[1], x[0]))负号表示降序元组第二个元素天然按字典序升序。一个直观的参考实现from collections import Counter s input().strip() counter Counter(s) # 按出现次数降序次数相同时按字母升序 result sorted(counter.items(), keylambda x: (-x[1], x[0])) for ch, cnt in result: print(f{ch}:{cnt})这道题真正的考点不是“会不会用哈希表”而是对排序规则的理解。我印象里不少人在这个看似简单的环节里出错因为没意识到“次数相同按字母顺序”这一步需要自定义比较器。3.2 第二道编程题任务截止时间与收益最大化第二题的场景是教育App里的“每日学习任务”有n项任务每项任务需要一天完成每个任务有一个截止时间d和完成后的收益p求能获得的最大收益。每天只能完成一项任务。这道题一出第一反应是“按收益从大到小选不就行了”这个贪心是错的因为高收益的任务可能截止时间在很后面如果先做了它反而浪费了前面几天。我当时在这个地方卡了五分钟后来换了一个思路按截止时间从小到大排序用一个最小堆维护“当前已选择的任务”。关键逻辑是遍历到截止时间为d的任务时如果当前已选任务数小于d直接加入堆如果已选任务数等于d就把当前任务的收益和堆里最小收益比较如果更大就把堆顶弹出、加入当前任务。这个思路的本质是“在同样的时间窗口内尽量保留收益更高的任务”。参考实现import heapq def max_profit(tasks): tasks.sort(keylambda x: x[0]) # 按截止时间排序 heap [] for deadline, profit in tasks: if len(heap) deadline: heapq.heappush(heap, profit) elif heap and heap[0] profit: heapq.heapreplace(heap, profit) return sum(heap) tasks [(1, 5), (2, 3), (2, 7), (3, 8)] print(max_profit(tasks)) # 输出 5 7 8 20这里最容易忽略的是“为什么按截止时间排序而不是按收益排序”。原因在于最小堆维护了一个可以随时调整的候选集合只有把截止日期相同的任务放在一起处理才能在同一个时间窗口里做“挤出最小保留最大”的替换。如果一开始按收益排序后续替换时会乱套。3.3 第三道编程题课程依赖关系的拓扑排序第三题虽然也带着教育场景但本质是一道拓扑排序给定课程数量和先修关系判断能否完成全部课程。每个依赖关系形如[a, b]表示修完b之后才能修a。这道题放在当年属于中等偏基础的水平。我当时的解法是用入度表BFS统计每个结点的入度把入度为0的结点放入队列每次弹出一个结点把它的所有后继结点入度减1如果减到0就入队。最后如果访问过的结点数不等于课程总数说明存在环无法完成。参考实现from collections import deque def can_finish(num_courses, prerequisites): graph [[] for _ in range(num_courses)] indegree [0] * num_courses for a, b in prerequisites: graph[b].append(a) indegree[a] 1 queue deque([i for i in range(num_courses) if indegree[i] 0]) visited 0 while queue: node queue.popleft() visited 1 for nxt in graph[node]: indegree[nxt] - 1 if indegree[nxt] 0: queue.append(nxt) return visited num_courses我在这道题上踩过一个很低级的坑依赖关系的方向。题目说的是[a, b]表示修完b才能修a也就是说b指向a构建邻接表时应该graph[b].append(a)。如果方向搞反整个入度统计就全错了。笔试时在草稿上把方向标清楚再动手比着急写代码更省时间。3.4 关于编程题的得分心态这三道题第一题属于“必须全对”第二题属于“需要一点思维拐弯”第三题属于“基础扎实就能过”。如果当时我在第二题上死磕太久很可能连第三题都来不及写完。所以后来者可以记住一个经验卷面编程题会有一个难度梯度不要在中间某道题上赌上全部时间先把能拿的分拿到手再回头啃硬骨头。在线判题环境有个特点不是AC就是0分没有部分得分。所以做出一道题的完整AC比三道题都写了半截要划算得多。如果你有时间复盘优先保证每道题都有完整思路并且跑通至少一个样例。4. 在线笔试环境的隐性失分点本地跑通和系统判题之间的鸿沟编程题最大的敌人往往不是算法本身而是在线判题环境的“输入输出规矩”。如果平时只在本地IDE里自己造数据很少用牛客这类平台做题很容易在以下三个位置丢分。4.1 输入读法的坑在线判题的输入可能是多行、多组用例也可能一行里有多个空格。用input()单行读取没有问题但多组用例时要注意循环次数不好确定更稳妥的做法是用sys.stdin.read()一次性读取全部内容再按行切分import sys data sys.stdin.read().strip().split()如果是Java用BufferedReader比频繁Scanner(System.in)更快尤其在输入数据量大的时候。这一条当年不太起眼但确实帮我在时间上省了很多。4.2 输出格式必须严格很多人忽略的一个细节是输出不能多一个空格、不能少一个换行、不能额外打印调试信息。有一次我在本地调试时习惯性加了一行print(debug: , result)改代码时忘了删提交后直接WA。在线判题按字符匹配结果任何多余输出都会被判错。所以提交前一定把调试代码全删干净只用print输出最终结果。4.3 边界条件的检查清单每写完一道编程题我习惯在草稿上检查一遍几个固定边界。这套清单纯靠临时想很容易遗漏但对照着过会快很多输入规模为0时程序是否会崩溃输入为1或最小值时算法是否正常数值会不会超出int范围是否需要long字符串是否可能包含空格入度为0的初始结点是否存在如果不存在答案是否直接为“无法完成”其中隐藏最深的坑是数组越界。比如动态规划的dp[i-1]在i0时直接数组越界Java会抛异常Python的负索引反而不会报错但会给出一个匪夷所思的答案。如果你用Python特别要注意负索引造成的“看似正确实则错误”的结果。4.4 递归深度限制拓扑排序这类题用BFS不会踩递归的坑但如果你用DFS写法Python默认递归深度大概在一千层左右课程数一多就会爆栈。一个常见改法是sys.setrecursionlimit(1000000)但这是治标不治本最好直接用迭代写法。笔试时与其和语言特性较劲不如选最稳妥的实现方式。5. 从这套卷看猿辅导的筛选逻辑它到底在找什么样的人回看整套试卷不难发现一个规律几乎没有一道题是“完全脱离场景”的裸算法题。字符串统计被包装成了作业查重任务收益被包装成了学习打卡拓扑排序被包装成了课程依赖。这不是为了增加阅读量而是在暗示一个信息这家公司希望工程师能把自己的技术能力迁移到真实的业务场景里去。5.1 技术考察的落脚点是“基本功工程感”2017年前后的许多公司笔试偏爱出“模型题”套路明显背过就会。但猿辅导这套题更偏向考察基本功的扎实度选择题里那些二叉树遍历、TCP状态、语言细节编程题里那些排序、最小堆、拓扑排序都是大学课程里反复强调的内容。它不指望你掌握冷门的高级算法而是确保你有足够扎实的计算机基础。这背后的逻辑也很清晰在线教育业务对系统的稳定性要求很高一个顶不住并发、边界条件处理不好的工程师上线时可能造成线上事故。笔试没有直接考高并发架构但通过编程题的边界值和输入输出细节已经在侧面观察你的工程素养了。5.2 场景包装题怎么答才能加分遇到披着业务场景的算法题你可以先承认自己理解了业务场景再回到算法本质。比如第二道“学习任务收益最大化”你在代码注释里写清楚“这个问题本质上是带截止时间的任务调度问题”虽然注释不影响判题但后续如果有面试官看你的答题记录这种做法会留下条理清晰的印象。5.3 给后来人的备考建议以这套卷为参照如果当年有人能提前告诉我这些事我会少走不少弯路基础理论必须能手推比如二叉树重构、状态变迁而不是只背结论编程题至少熟练掌握字符串排序、动态规划、拓扑排序这几个高频考点每周固定在OJ平台上做一到两套完整试卷训练在有时间压力的情况下分配精力的能力每次做完题目把WA的用例记录下来整理成自己的坑位清单。这套卷子对我个人的意义不只是“一次校招笔试”这么简单。它让我第一次意识到在线笔试不是一场纯粹的知识考试它同时考你的时间管理、心态控制和代码习惯。后来再看任何校招笔试我都会用同样的思路去拆解先看卷面结构再分配时间做题时留好边界检查的余量。这个习惯是从2017年这场笔试开始养成的。
返回列表