
2019年秋招季我在牛客网刷到自如的技术岗校招笔试。那会儿自如正处在业务快速扩张阶段技术岗笔试走的是主流互联网公司的套路线上笔试、随机出题、选择题加编程题的组合。B卷是跟A卷平行的另一套题目形式上完全一样但具体考点和题目细节会有差异用来防止同考场的人互相参考。这篇算是对当年B卷的一次完整复盘把题型结构、高频考点、编程题解题思路、选择题易错点都整理出来顺便聊聊这种校招笔试到底在筛什么样的人给后面准备自如技术方向或者其他互联网公司校招笔试的朋友做一个参考。1. B卷到底考什么先看整体考情与题型结构1.1 试卷构成与时间分配自如技术方向的B卷整体结构和大多数互联网公司笔试类似分客观题和编程题两大部分。客观题一般是20到30道覆盖计算机网络、操作系统、数据库、编程语言基础、数据结构与算法编程题通常是2到3道难度跨度比较大第一道往往是简单到中等难度的字符串处理或模拟题后面会出现需要动点脑筋的贪心、动态规划或区间类问题。整套卷子限时一般在90到120分钟实际写起来时间很紧尤其是选择题如果卡太久编程题很容易做不完。我当年做这套卷子的时候时间分配上吃了个小亏。前面选择题里有两道多选反复纠结耗了将近20分钟结果最后一道编程题只来得及写完主体逻辑没时间跑用例交上去心里特别没底。后来复盘时总结出一个相对稳妥的分配方式客观题控制在45到50分钟内剩下70分钟全部留给编程题。选择题里面一旦出现一眼看不出来的先标记回头再看别恋战。毕竟编程题分值高且只要思路对、能跑通用例拿到的分数远比死磕两道选择题来得划算。1.2 B卷和A卷的差异点在哪很多人关心A卷和B卷到底有什么区别。从当年周边同学分享的情况来看两套卷子的考点范围基本一致都是那几大块但题序、题干细节、具体数值和部分题目会做替换。比如A卷考了某道关于TCP三次握手的状态变化B卷可能换成TCP四次挥手A卷编程题出现“字符串去重排序”B卷可能变成“字符串按指定规则压缩”。这种情况意味着你没法靠“背试卷”来准备必须把核心知识点本身吃透。还有一点值得注意B卷通常有一两道题会和实际业务场景挂钩。自如的业务本身涉及房源、合同、维修工单、租客服务这些场景所以笔试题里偶尔会出现类似“合并租期重叠区间”“对日志记录按时间排序”“处理一批超长数字字符串求和”这类接地气的题目。本质上还是考基础算法但题干包装会更贴近业务读题时要学会剥离场景快速识别出它真正在问什么。1.3 笔试平台与答题体验当年自如用的在线笔试系统是第三方平台支持代码运行和在线调试但也有一些限制。比如有的平台只支持单文件提交不允许多个类键盘监听和代码补全功能很弱基本等于一个带高亮的文本编辑器。这些都会影响实战手感建议提前去牛客网的在线编程模块做几套模拟题适应一下没有IDE自动补全的环境。另外在线笔试对网络的稳定性要求很高。我身边真有同学因为断网导致答案没提交上最后只能联系HR补考。虽然现在一般在稳定的环境下基本不会出问题但保险起见开考后先花两分钟确认代码提交按钮、语言编译环境是否正常再开始做题。这个习惯我一直保持到后来的每一场在线笔试真的能避免很多意外。2. 选择题高频考点计算机网络、操作系统、数据库一次理清2.1 计算机网络不只是背三次握手计算机网络这块几乎是校招笔试的固定板块B卷里大概会出5到8道题。最常考的包括TCP与UDP的区别、TCP握手和挥手过程、HTTP状态码含义、DNS解析流程、HTTP与HTTPS的区别等。很多同学背得滚瓜烂熟但一到具体题目就翻车。比如“TCP建立连接需要几次握手为什么不是两次”这种题表面考握手次数实际考的是对可靠传输和同步序列号的理解。我当年遇到的一道B卷题是在TCP第三次握手时客户端发送的报文段如果丢失会发生什么正确答案需要清楚TCP的重传机制服务器会超时重传SYNACK而不是直接断开连接。这种细节如果不真正理解报文交互过程光靠背是不行的。备考建议是把TCP报文的标志位、状态转换图自己画一遍把每个状态下的收发情况捋清楚。HTTP状态码也要记牢尤其是3xx重定向类、4xx客户端错误类、5xx服务端错误类B卷很喜欢在选项里混入201、301、403、502这类状态码考察你是否知道它们分别代表什么。2.2 操作系统死锁、线程与调度都是送分题还是送命题操作系统部分常考进程与线程的区别、死锁产生的必要条件、进程调度算法、页面置换算法、内存管理方式等。这些内容在本科课程里都学过但笔试难度在于概念辨析和条件边界。死锁那四要素互斥、持有并等待、不可剥夺、循环等待是高频中的高频B卷中通常以多选题形式出现问“下列哪些是死锁产生的必要条件”或者“下列哪种策略能破坏死锁的循环等待条件”。我见过不少人把“资源分配图没有环”这种额外条件也选上去结果扣分。这里要记清楚破坏循环等待条件不等于破坏其他三个条件。线程和进程的对比也是个重灾区。选项常常出现“线程是资源分配的基本单位进程是调度的基本单位”这种说法反了进程才是资源分配的基本单位线程是CPU调度的基本单位。还有协程、用户态和内核态的切换、上下文切换开销等虽然出现频率略低但B卷偶尔会涉及。2.3 数据库SQL会写不代表能拿分数据库部分主要考SQL语句和事务特性。常见题型有给定两张表问某个查询语句的结果给出多表连接条件判断该用内连接还是左连接关于事务隔离级别判断哪种隔离级别能避免脏读、不可重复读、幻读。我印象比较深的一道B卷选择题是考察索引失效的。题目给了几个查询条件问哪个能命中索引选项里有对索引列做函数运算、对列进行隐式类型转换、使用LIKE通配符开头等场景。这道题其实在考B树索引的工作原理如果你只知道“索引能加速查询”而不清楚最左前缀原则和存储结构很容易踩坑。SQL优化类的题目也越来越常见比如给定一个慢查询问如何优化。常见的答案有加索引、避免SELECT *、避免在WHERE子句中对列使用函数、小表驱动大表等。建议准备时把数据库的三大范式、四种隔离级别、索引原理、常用聚合函数和连接查询都过一遍基本就能覆盖这类题目。2.4 语言基础与数据结构Java高频题比较多编程语言方面B卷对Java考察比重比其他语言高一些选择题里会出现String、StringBuilder、StringBuffer的区别HashMap底层实现ArrayList和LinkedList的增删查复杂度对比Java异常体系等。C也会考但一般集中在指针、内存管理、虚函数、const的作用这些点。数据结构部分必考的有栈和队列的特性、二叉树的前中后序遍历、哈希表冲突处理方式、快速排序和归并排序的时间复杂度与稳定性。这里建议把各类排序算法的平均时间复杂度、最坏时间复杂度、空间复杂度、是否稳定整理成一个表考前快速过一遍效率很高。有个特别容易踩坑的点是HashMap。JDK1.8之后HashMap在链表长度大于等于8且数组长度大于等于64时会树化转成红黑树当节点数降到6时会退化为链表。这个“8”和“6”之间的差值经常被拿来出题如果没记清楚很容易被选项绕进去。另外HashMap在多线程下扩容可能出现死循环这是JDK1.7时期的问题1.8做了优化但仍不保证线程安全并发场景要用ConcurrentHashMap这些都是B卷选择题的常客。3. 编程题实战拆解三道典型题从读题到AC3.1 字符串压缩第一道题最常见的类型B卷编程题的第一道通常是简单偏中等难度的题目字符串压缩就属于这类。题目大致意思是给定一个字符串把连续出现的相同字符按“字符出现次数”的方式压缩比如aabcccccaaa压缩成a2b1c5a3如果压缩后的长度不小于原字符串长度则返回原字符串。这道题本质上是纯粹的模拟和边界处理不涉及复杂算法但极考验编码基本功。我当年拿到这题时思路很简单从左到右遍历字符串维护当前字符和计数遇到字符变化就把之前的字符和计数拼到结果里最后再处理最后一组字符。代码用Python写大概是这样def compress(s: str) - str: if not s: return s 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]会越界。第二、计数是int类型拼接时一定要转成字符串。第三、判断“压缩后长度不小于原字符串长度”时题目里说的是“不小于”那就意味着压缩后长度要严格小于原串长度才返回压缩结果等于的时候要返回原串。很多人在这个等号上出错。这类题在笔试中非常典型它考的不是你会不会某个算法而是代码写得稳不稳、边界有没有考虑全。建议所有刷题的人养成一个习惯核心逻辑写完后先手动跑几个边界用例比如空串、全相同字符、相同字符打散的情况。3.2 合并区间B卷业务场景题的代表第二道题我遇到的是合并区间题干包装成了“将多个租期重叠的订单合并成一个连续时间区间”但剥掉外壳后就是经典算法题“合并区间”。这道题在LeetCode上是Medium难度核心考察排序和贪心思想在自如这种有房源租期管理的业务里出现非常合理。题目要求是给定一个区间集合把有重叠的区间合并返回合并后的不重叠区间列表。我的解法是先把所有区间按左端点排序然后依次遍历。用一个列表维护结果如果当前区间的左端点小于等于结果中最后一个区间的右端点说明有重叠需要更新右端点为二者中更大的值否则直接加入结果。代码实现如下def merge(intervals): if not intervals: return [] intervals.sort(keylambda x: x[0]) res [intervals[0]] for left, right in intervals[1:]: if left res[-1][1]: res[-1][1] max(res[-1][1], right) else: res.append([left, right]) return res这里有个细节要注意如果区间是引用类型直接res.append(intervals[0])时后续对res[-1][1]的修改可能影响到原数组元素。在Python里int是不可变对象但列表本身是可变引用如果后续在原列表上做修改可能会产生副作用。笔试时为了稳妥可以复制一份再操作避免编辑器或判题机对内存共享的检查。这道题进一步扩展还有“插入区间”“求重叠区间最大数量”等变体。如果时间充足建议把这类区间问题放在一起刷理解贪心思想之后变化不大。对我个人来说这类题是最值得花时间准备的因为它在校招笔试里出现频率高从大厂到独角兽都喜欢考。3.3 大数相加用模拟题检验细心程度B卷第三道编程题我遇到的是大数相加。题目给两个超出long范围的数字字符串要求返回它们的和字符串长度可能达到几百甚至上千位。这道题不涉及什么高深算法核心就是模拟我们小学数学里的竖式加法考察对字符串操作、位数对齐和进位的处理能力。代码写出来很简洁def add_strings(num1: str, num2: str) - str: i, j len(num1) - 1, len(num2) - 1 carry 0 res [] while i 0 or j 0 or carry: digit1 int(num1[i]) if i 0 else 0 digit2 int(num2[j]) if j 0 else 0 total digit1 digit2 carry carry total // 10 res.append(str(total % 10)) i - 1 j - 1 return .join(reversed(res))别看代码短实际错误率很高。最常见的坑有两个一是循环条件漏掉carry导致最后还有一位进位时直接退出比如999加1应该得到1000但如果不管carry就会得到000这种危险结果二是最后忘记反转列表或者试图用字符串拼接不断insert到头部导致时间复杂度变成O(n^2)。笔试环境下数据量大时这种低效写法很可能超时。做这道题给我的经验是模拟题不是“简单题”它更像“细心题”。读题时先确认有没有负数、有没有前导零、是否允许输出前导零这些条件稍微变一点代码的边界逻辑就完全不同。考试时宁可多写两行注释也别偷懒省略边界判断。4. 笔试现场容易踩的坑环境、时间与答题策略4.1 多选选择题的计分规则必须先搞清楚很多同学在笔试时根本没注意到多选题计分规则导致答题策略完全错误。我参加的那场B卷多选题是漏选得部分分选错不得分。这意味着如果你不确定某个选项是否正确最好的策略是选自己有把握的不要为了凑分去赌一个不确定的选项。一旦选错整道题零分还不如少选一个拿一半分。但有的平台是少选不得分、必须全对才给分那策略就完全不同。开考后第一件事先看考试说明特别是多选计分规则和大题分值分布。这个信息通常藏在试卷页面的顶部或侧边栏花30秒看清楚比你多做一道选择题更有价值。竞赛、考试都是信息战规则里包含的信息不利用就亏了。4.2 编程题先写主流程再补边界在线笔试的判题系统一般会跑多个测试用例其中包括不少边界用例。如果一开始就试图把所有细节都考虑周全很容易陷入细节出不来。我个人的习惯是先把核心逻辑写出来保证示例能跑通再逐步补充边界处理。比如字符串压缩那题先忽略空串和单字符的情况把主循环写出来跑通样例后再加上前面两个特判这样心态会比较稳。还有一点笔试平台支持多次提交但有的平台对提交次数有限制或者有罚时机制。遇到这种情况不要“交一版试一次”地反复提交自己先在本地把可能出现的用例跑一遍确认无误后再提交。我见过有人因为提交超过次数限制结果无法修改代码只能眼睁睁看着编译错误扣分非常可惜。4.3 常见环境问题与应对在线笔试平台容易出现几类问题代码编译不过、运行超时、输入输出格式错误。编译不过主要集中在语言版本差异比如本地用Python3.9的语法平台只支持Python3.6f-string里嵌套字典解包这种高级写法就会报错。所以开考前可以先用最简单的print(hello)测试一遍环境确认没有语法兼容问题再开始答题。输入输出格式错误也很常见尤其是有多行输入时很多人习惯用input()一次读一行但题目可能要求读完所有行再输出。最稳妥的方式是用sys.stdin.read()一次性读入所有内容再按规律解析。虽然代码稍微长一点但能避免漏读多读导致用例全部失败的问题。前提是掌握正确的读取方式别反过来因为解析出错。4.4 实在不会做的题蒙题也有策略选择题不会做时排除法永远是第一原则。在B卷这种随机出题的场景里四个选项中往往有两个一眼就能看出明显错误剩下两个再结合知识点判断。如果完全不会比如操作系统的一道冷门调度算法题可以根据选项长度、常识倾向去猜但这是下策不能依赖。更重要的是遇到不会的题不要慌标记后跳过先保证会的题都拿到分后面有时间再回头思考。5. 复盘B卷背后真正考察的能力模型5.1 基础知识的体系化程度决定你的下限如果只刷题不总结笔试成绩往往不稳定。回顾B卷我觉得它从头到尾都在考察一件事基础知识是否成体系。零散地记住“HTTP状态码有204”“HashMap负载因子是0.75”并不够考场上题目会把这些知识点放在具体场景里让你判断哪种说法是正确的、哪种处理方式是合理的。只有理解知识之间的联系才能不被选项的表述带偏。我当时把计算机网络、操作系统、数据库、数据结构和算法这几门课的核心知识点分别整理了思维导图考前把图整体过一遍效率比翻书高很多。思维导图不需要多精美重点是让知识形成网络比如从TCP的三次握手能联想到SYN Flood攻击从HashMap能联想到ConcurrentHashMap的分段锁机制这样选择题里出现任何交叉考点你都能迅速定位到对应的知识源。5.2 编码基本功和边界意识决定你的上限编程题虽然占分比不一定最高却往往是简历筛选之后面试官最关注的部分。因为选择题可以通过短期突击背出来编程题则能看出你的编码习惯和思维深度。B卷三道编程题难度都不算高但覆盖了模拟、贪心、字符串处理三种类型有一个共同点光写出正确逻辑还不够还要能处理各种边界情况。边界的本质是对问题定义的深刻理解。字符串压缩时为什么判断条件要写“压缩后长度小于原字符串”因为题目要求“压缩后的长度不小于原字符串则返回原串”这个条件意味着等于也要返回原串。大数相加时为什么循环条件要包含carry因为最后一位进位不能被丢掉。这些细节恰好是面试官在简历上看不到、只能在机试中观察的能力。5.3 准备校招笔试的节奏建议针对自如这类技术岗笔试复习节奏可以分成三个阶段。第一阶段是全面梳理把计算机网络、操作系统、数据库、数据结构与算法的基础知识点过一遍不求深但求全第二阶段是刷题强化重点刷LeetCode的Hot 100和牛客网上各家公司的真题每道题控制时间刷完及时总结题型第三阶段是模拟实战用牛客网的模拟笔试功能或求职辅导平台的在线笔试系统至少完整模拟两套试卷提前适应时间分配和平台操作。B卷虽然已经过去很久但校招笔试的考察逻辑几乎没有变过。基础知识是否扎实、编程题能否熟练处理边界、考场时间够不够用永远是技术岗笔试的三个核心维度。希望这篇文章能帮你把这三个维度的问题提前想清楚少踩一些我当年踩过的坑。