快手这家公司,从短视频到直播,再到后来的电商和本地生活,技术体系的复杂度是逐年攀升的。正因如此,它家的校招笔试题目,一向在“工程落地”和“基础功底”之间找平衡。2019年秋季那场校园招聘笔试的工程B试卷,虽然过去几年了,但回过头来看,里面的出题思路、考察重点,跟现在大厂的工程岗笔试套路几乎一脉相承,甚至可以说是很多后来者的“模板”。我当时认真刷过这套卷子,也陪着几届学弟学妹复盘过,今天就把这套工程B试卷的考察逻辑、核心考点和现场答题策略,掰开揉碎讲清楚。
这套卷子适合谁看?如果你是正在准备大厂校招的应届生,尤其是后端、基础架构、客户端方向的工程岗,那这份复盘能帮你少走不少弯路。如果你只是对大厂笔试好奇,想看看他们到底筛选什么样的人,这篇文章也能给你一个比较直观的参考。我会从试卷结构、算法题、计算机基础、语言特性、系统设计、智力题这几个维度,逐一拆解,中间穿插一些我自己刷题和面试时的真实体会。
1. 工程B试卷的整体面貌与出题逻辑
很多人拿到这套卷子,第一反应是“题量怎么这么大”。其实快手这类互联网公司的校招笔试,从来不是让你把每道题都做完,而是在有限时间内考察你的“优先级判断力”和“抗压能力”。工程B试卷整体分成了几大块,包括客观选择题、手写编程题、系统设计题,以及一部分逻辑智力题。考试时间一般卡在90到120分钟,题量通常在10道选择、2到3道编程、1道设计题左右,外加几道小题。
1.1 题目结构与时间分配建议
从结构上看,选择题覆盖的知识面非常广,包括数据结构、操作系统、计算机网络、数据库、Java或C++语言特性,甚至还有一些概率论的基础题。这部分是“快问快答”类型,平均每道题不能超过2分钟。有些题就是纯粹考察概念,比如TCP三次握手的状态变化,或者HashMap在JDK 7和JDK 8之间的区别,这些背过就有分,但没复习过就真的只能靠蒙。
接下来是编程题,这部分通常是2到3道算法题,难度从LeetCode中等偏易到中等偏难不等,偶尔会有一道压轴的偏难动态规划。快手工程B试卷的编程题,一般不会出那种纯数学推导的偏题怪题,更多是考察你“能不能把常见的数据结构用熟”。比如树的遍历、图的最短路径、贪心、双指针、前缀和之类的,都是高频区间。
系统设计题则非常有意思,通常会给一个具体的业务场景,比如“设计一个短链接服务”或者“设计一个关注列表的推送系统”,让你用一两页纸去描述方案。这道题不要求你写出完整代码,但对你的架构思维、技术选型和边界考虑要求很高。很多第一次参加笔试的同学,会在这道题上严重翻车,因为平时的刷题训练根本覆盖不到这个维度。
1.2 为什么快手会这么出题
快手当时的业务增长很快,用户量巨大,加上视频和直播的场景极其依赖推拉流、上传下载、实时互动,所以他们对工程同学的要求很明确:基础必须扎实,在分布式环境里能处理问题,同时能写一手干净的代码。工程B试卷的“B”大概率对应的是后端或者基础工程方向,所以考察内容会更偏服务器、存储和中间件这些领域。
这套卷子筛的不是“你背了多少面试题”,而是“你有没有形成计算机的底层知识框架”。你会发现选择题里很多题目是在交叉考察,比如操作系统里的页面置换算法,会结合到设计缓存时的淘汰策略;网络里的拥塞控制,会跟分布式系统中的流量控制结合起来。如果只是死记硬背,很难拿到高分。
2. 算法与数据结构:笔试的主战场
算法题永远是笔试中最拉分的部分,工程B试卷也不例外。快手这类公司面试官阅卷时,对算法代码的评判标准通常不是单纯看“对不对”,而是看“复杂度是否达标”和“代码风格是否成熟”。同样一道题,暴力解法可能AC不了最后一个大数据用例,但优化解能全过。
2.1 高频题型的考察思路
从这套卷子反映出的出题倾向来看,有几种题型几乎年年出现。第一种是“数组与哈希表”的组合题,比如“给出一个数组,找出和为target的两个数下标”。这种题看起来简单,但快手通常会在边界条件上埋坑,比如数组可能包含负数,比如要求返回下标的字典序最小组合。第二种是“二叉树相关问题”,比如最近公共祖先LCA、层序遍历、路径求和。树的题考察的是递归和迭代两种写法,如果你只会递归,遇到深度极端的用例可能爆栈。
第三种是“贪心与动态规划”,这是区分度最大的一块。工程B卷压轴算法题往往是一道中等偏上的DP,比如“编辑距离”“最长上升子序列”“打家劫舍变种”等。这类题光知道状态定义还不够,还要能准确推导转移方程,并考虑状态压缩的空间优化。很多同学能在十分钟内看出是DP题,但状态定义一错,后面全崩。
第四种是“图论基础题”,比如拓扑排序、并查集判断连通分量、Dijkstra最短路。这里要特别提醒,快手笔试的ACM模式跟LeetCode的核心代码模式不一样,输入输出需要自己处理。很多同学在ACM模式下会紧张,明明思路对,结果卡在读取输入或者格式化输出上。
2.2 从暴力到最优的答题策略
我在实际操作中有一个经验:拿到算法题,如果5分钟内没有清晰思路,先写一个暴力解保底,哪怕只能过一部分用例,也能拿到部分分数。笔试判卷通常是按通过用例比例给分,不是零一制。写完暴力解后,再回头优化,不要一开始就死磕最优解,导致最后时间耗尽一道题都没交。
以一道典型的“最大连续子数组和”为例,暴力解是三层循环枚举起点、终点并求和,复杂度O(n^3),这种代码用来保底,但肯定超时。然后可以用前缀和优化到O(n^2),用数组sum[i]表示前i个元素的和,子数组和直接用sum[j]-sum[i]得到。最后的最优解是Kadane算法,也就是动态规划的一维版本,维护一个cur变量,表示以当前元素为结尾的子数组最大和,cur = max(cur + nums[i], nums[i]),同时用global_max记录全局最大。这道题之所以高频,是因为它从暴力到动态规划的进化路径非常清晰,可以考察候选人的思维梯度。
2.3 一个典型题目的现场推导
我拿一道类似工程B卷风格的题目示例一下推导过程。题目是“给定两个有序数组,找出合并后的中位数”,要求时间复杂度O(log(m+n))。这道题如果直接合并两个数组,复杂度O(m+n),不算错,但O(log(m+n))的要求直接指向二分法。
核心思路是对较短的数组二分划分位置,通过中位数的性质,确定另一个数组的划分位置,使得左右两部分元素个数相等,且左边最大值小于右边最小值。这里最大的坑是边界条件,比如某一个数组完全在左边或右边,需要设置哨兵值去处理。写代码时,我会习惯性地加上注释,说明每个边界判断的含义,这样阅卷人一眼就能看出你懂原理。
笔试阅卷还有一个隐形的加分项:变量命名清晰,函数拆分合理。如果所有逻辑都堆在main函数里,变量名都是a,b,c,d,即使算法对了,印象分也会打折扣。反过来,代码结构清爽,有合理的函数划分,容易让阅卷人对你的工程能力产生信任。
3. 计算机网络、操作系统与数据库:工程基本功
工程B卷的选择题和简答题里,计算机基础占了很大比重。这部分不能靠临时抱佛脚,必须形成体系。我见过太多同学算法题做得飞起,但一问TCP和UDP的区别,只能说“TCP可靠、UDP不可靠”,这种颗粒度远远不够。
3.1 计算机网络怎么复习才够用
网络部分,工程B卷反复出现在这几个知识点上:TCP三次握手与四次挥手的状态变迁、TCP的拥塞控制(慢启动、拥塞避免、快重传、快恢复)、HTTP与HTTPS的差异、DNS解析过程、TCP粘包问题、HTTP/2的多路复用等。其中TCP状态变迁几乎是必考,比如你知道TIME_WAIT出现在主动关闭方还是被动关闭方?答案是主动关闭方,在收到对端的FIN后,进入TIME_WAIT状态,持续2MSL以确保最后的ACK可达,并让旧连接中的报文自然消失。2MSL的时长一般在1到4分钟之间,具体看系统实现。
HTTP与HTTPS的差异,不能只从“加密”两个字回答,要能把握手流程讲清楚。HTTPS额外使用了TLS协议,握手时先做证书校验,再交换密钥,后续通过对称加密传输数据。这里还有一个高频追问:HTTPS一定安全吗?答案是否定的,如果客户端没有校验证书或者被安装了恶意根证书,中间人攻击依然可能成功。所以考核这个知识点,本质上是在考察你是否真正理解“安全是分层的”。
UDP在快手这类流媒体公司里地位很高,因为视频直播场景大量使用UDP或者基于UDP的QUIC协议。这里问一个深的:TCP的粘包和拆包是怎么回事?原因是TCP是字节流协议,没有消息边界,应用层需要自己定义消息格式,常见的解法是定长消息、分隔符、或者长度字段前缀。推荐的做法是长度字段前缀,比如4字节的int表示消息体长度,这也是很多RPC框架的做法。
3.2 操作系统的一些高频考点
操作系统里的高频考点,主要集中在进程与线程的区别、死锁的四个必要条件、虚拟内存与页面置换算法、进程通信方式。这些概念要能说出“What”“Why”“How”三层。
比如死锁,光知道四个必要条件(互斥、持有并等待、不可剥夺、循环等待)是不够的,要能解决实际问题。笔试经常会出这样的题:银行家算法里,给定可用资源向量和每个进程的已分配资源与需求资源,判断系统是否处于安全状态。解这种题要按顺序模拟,选择满足需求且能释放资源的进程执行,直到所有进程都能完成。如果找不到这样的进程,就说明不安全,可能死锁。
虚拟内存的面试题则会更贴近实际:为什么需要虚拟内存?核心原因是让多个进程可以共享物理内存,同时提供隔离和扩展。页面置换算法里,LRU是考察重点,但工程实现一般不会用时间戳,而是用双向链表加哈希表,保证O(1)复杂度。这个思想对应到算法题,就是LeetCode的LRU Cache,工程B卷的算法题如果考这个,务必提前练熟。
进程通信方式也是高频区,管道、消息队列、共享内存、信号量、Socket各有适用场景。笔试有时会问“为什么共享内存效率最高”,答案是因为不需要内核拷贝数据,但需要同步机制保护。这个问题一旦展开,就又回到了并发控制上,可见这些基础都是串联的。
3.3 数据库:一线工程师必须懂的索引与事务
数据库题的出题思路通常非常“业务化”,围绕索引失效、事务隔离级别、悲观锁与乐观锁、SQL书写与优化展开。作为工程岗,数据库是躲不开的存储基础,所以这部分得分率往往能反映真实水平。
索引那一块,必考B+树为什么适合做数据库索引。你至少要说清楚三点:树矮、磁盘IO次数少;叶子节点形成有序链表,适合范围查询;所有数据都在叶子节点,查询性能稳定。还要知道聚簇索引和非聚簇索引的区别,InnoDB的聚簇索引就是主键索引,叶子节点存放整行数据;非聚簇索引的叶子节点存放主键值,因此查询非索引字段的时候需要回表。
索引失效的场景在选择题里出现概率极高。常见的判断规则有:最左前缀原则、在索引列上做函数操作会导致失效、隐式类型转换会导致失效、用不等于或者like左模糊会导致失效。我记得有一道题是这样设计的:给一个联合索引(a,b,c),问下面几个查询里哪些能命中索引。只要记住最左前缀,再加上“遇到范围查询后面的列会失效”,基本就能答稳。
事务方面,ACID四个特性要能解释清楚,尤其是隔离性如何通过锁和MVCC实现。四个隔离级别的脏读、不可重复读、幻读问题要一一对应。这里有个容易混淆的点:可重复读级别在MySQL的InnoDB下是否能解决幻读?答案是大部分情况能,因为Next-Key Lock锁住了范围,但在某些特殊场景下仍可能出现幻读。面试官如果追问到这个深度,已经不只是笔试的范畴了。
4. 语言特性与手写代码:工程感的直接体现
工程B试卷一般会让你选择熟悉的语言,Java、C++、Python、Go都可以,但每个语言背后的运行机制,考察深度完全不同。快手后端早期以Java为主,所以Java方向的题目相对更多,但C++和Python的题也不少见。
4.1 Java方向的高频考点
对于Java方向,HashMap几乎年年上榜。要掌握的点包括:JDK 7和JDK 8在数据结构上的差异(数组加链表 vs 数组加链表加红黑树)、扩容机制(默认容量16,负载因子0.75,扩容为原来的2倍)、put方法的大致流程、为什么链表长度超过8会转红黑树(为了抵消哈希碰撞恶化时的性能损失)。还要知道HashMap不是线程安全的,多线程扩容时JDK 7版本可能形成环形链表导致死循环,JDK 8虽然修了这个问题,但并发下仍然可能丢失数据,所以并发场景要用ConcurrentHashMap。
JVM内存结构也是重点。堆、虚拟机栈、本地方法栈、方法区(元空间)、程序计数器,每一块存什么、会抛出什么异常,都要清楚。笔试喜欢设陷阱的题目是:判断一个对象是否“死亡”用的是可达性分析,而不是引用计数法,因为循环引用问题在引用计数下无法解决。G1垃圾回收器在JDK 9之后成为默认垃圾回收器,它的Region划分、可预测停顿、并发标记等,都是加分项。
线程池的一堆参数,也是从笔试到面试的多发区。核心线程数、最大线程数、非核心线程存活时间、任务队列类型、拒绝策略,为什么线程池不允许用Executors.newFixedThreadPool?因为默认的任务队列是无界LinkedBlockingQueue,极端情况下会堆积大量请求导致OOM。规范的做法是用ThreadPoolExecutor手动创建,指定有界队列和合理的拒绝策略。
4.2 C++与Python方向的常见考点
如果你选择C++,虚函数表、智能指针、STL容器复杂度、std::move和完美转发这些话题是绕不开的。智能指针里shared_ptr的引用计数是不是线程安全的?答案是引用计数本身是原子的,但指向的对象不是,所以多线程读写同一个shared_ptr保护的对象时,依然要加锁。C++的题往往会多一些内存细节的考察,比如struct的对齐规则。
Python方向则更关注GIL、list与dict的时间复杂度、装饰器、生成器、深拷贝与浅拷贝。GIL的问题尤其容易出成简答题:多线程爬虫在Python里是不是一定能加速?答案是在CPU密集任务下并不能,因为GIL同一时刻只允许一个线程执行Python字节码,真正的并行需要多进程。但在IO密集任务下,多线程因为释放GIL依然有优势。
4.3 手写代码题的现场得分技巧
笔试手写代码,不是写出来就完了,还要注意可读性和鲁棒性。我的一个习惯是:写之前先在草稿纸上把边界条件列出来,比如链表为空、数组只有一个元素、整数溢出等,然后再动笔写正式代码。另一个习惯是写完代码后,自己跑一遍边界用例,在注释里标注一下输出,能明显减少低级Bug。
快手工程B卷的手写代码题,出现过类似“复制带随机指针的链表”“判断一棵树是否是二叉搜索树”这类题目。这些题,最优解虽然不难,但边界细节很多。以复制随机指针链表为例,最优解一般是在原链表每个节点后面复制一个新节点,然后重新设置random指针,最后拆分链表。写代码时,拆分那一步特别容易写错,务必要用prev指针维护前一节点。
5. 系统设计与场景题:拉开层次的关键
很多同学看到系统设计题就懵,实际这恰好是工程B卷里最有意思的部分。因为这道题没有标准答案,但可以通过你的回答,看出你是否有完整的架构思维和工程判断力。
5.1 一个经典设计题的答题框架
工程B卷曾出现过的系统设计题目,我印象比较深的是“设计一个短链接系统”。这道题看似简单,实际上可以从多个维度衡量候选人。我是按照下面这个框架来作答的:
首先是需求分析,明确核心功能是把长链接生成短链接,以及短链接跳转到长链接。接着要估算QPS和数据量,如果公司每天有100万条新链接生成,短链接的跳转量可能是生成量的100倍,也就是1亿次每天,折算下来约1160 QPS,峰值可能是这个的3到5倍。数据存储上,如果把短码设为7位62进制,可容纳62^7个组合,大约是3.5万亿,完全够用。
生成短码的方案有很多,我会优先提发号器方案,用数据库自增ID或者Snowflake算法生成全局唯一ID,再把ID转成62进制字符串。为什么不用随机MD5截断?因为可能出现碰撞,需要重试,且无法保证短码有序。发号器方案的另一个好处是短码有趋势递增性,有利于数据库索引优化,同时方便做分库分表扩展。
跳转的存储层,可以设计成一张短码到长链接的映射表,读多写少,所以可以加一层Redis缓存,缓存未命中再查MySQL,同时通过布隆过滤器拦截不存在的短码,防止缓存穿透。整个架构画下来,再补充分布式ID的高可用、缓存淘汰策略、过期链接清理方案,这道题基本上就稳了。
5.2 场景题如何体现工程思维
场景题考察的核心不只是你会多少技术,而是你的“工程折中”意识。比如设计一个关注列表推送系统,有人上来就写Kafka、Flink、推拉结合,但如果不解释为什么“大V粉丝多需要拉模式,普通用户粉丝少用推模式”,那方案就只是名词堆砌。
我认为比较好的作答方式是:先给问题分层,再对每一层说明权衡。第一层是数据模型,关注关系如何存储,是A关注B还是B被A关注,如何用MySQL存大规模关系。第二层是推送时机,是用户发视频时触发,还是定时扫描,还是粉丝拉取时实时计算。第三层是实时性要求,比如快手这种视频App,用户希望看到关注的人最新动态,所以延迟控制在秒级。最后是容量规划,结合用户量、关注关系数量等估算存储和带宽。
这种逐层拆解的习惯,本质上就是一种工程思维。笔试时即使时间不够,把每一层写上一两句,也比整页只画一个框强得多。
6. 智力题与综合素质:别在阴沟里翻船
工程B试卷里偶尔出现的智力题,本质上是考察逻辑推理和数学敏感度。这类题不需要特别准备,但只要掌握几个常见模型,就能稳定得分。
6.1 概率题的常见模型
比如“一个家庭有两个孩子,已知其中一个是女孩,求另一个也是女孩的概率”。很多人脱口而出1/2,正确答案其实是1/3,因为样本空间是(男男、男女、女男、女女),已知一个是女孩,排除男男,剩下三个等可能,女女只占一个。这种题考察的是条件概率的基本概念,如果这个都不稳,说明概率论基础还需要补。
再比如“100层楼两个鸡蛋问题”,这是经典动态规划题,笔试有时会以选择题形式考到。核心思路是设置一个最大尝试次数k,第一次从第k层扔,第二次从第2k-1层扔,依次递减,使得总次数不超过k。解不等式k(k+1)/2 >= 100,得到k的最小值是14,这是最优解。能把推导过程写出来,比直接背答案更有说服力。
6.2 时间分配与心态管理
笔试题量大,时间紧,最重要的一步就是“学会策略性放弃”。我的建议是,优先做你熟悉的题型,先把该拿的分拿到,再去啃硬骨头。如果一道题卡了10分钟,果断跳过,最后有剩余时间再回头推。笔试是排位赛,不是满分赛,你做不出来的题,绝大多数人同样做不出来,但如果你因为一道题浪费太久导致后面全崩,那就完全得不偿失了。
另外,注意选择题的“单选”和“多选”提示。工程B卷这类试卷经常出现“多选”题,少选通常不得分或者得部分分,所以拿不准的选项不要乱选。我在实际监考中见过太多同学,明明知道正确选项,却被错误的干扰项迷惑,多选了一个答案,整题零分,非常可惜。
7. 实用备考建议与心态调整
笔试考的不只是知识储备,还有临场状态和策略。经历过秋招的人都知道,那一两个月是“身体和心态的双重消耗战”,尤其是工程B卷这种综合性强的试卷,提前做好规划很重要。
备考方面,我建议按“算法 + 基础 + 项目”三条线并行复习。算法线每天保持1到2道LeetCode,重点刷数组、链表、树、动态规划和图论;基础线每周安排固定时间看《计算机网络》《操作系统》的重点章节,可以用思维导图做总结;项目线要把自己简历里的项目吃透,能画出系统架构图,能说出每一项技术选型的理由。笔试只是第一关,之后的面试一定会深挖项目。
还有一点,做题之后一定要复盘。我会把错题按知识点分类,整理成自己的“错题本”,每周过一遍。其实大厂的考点就那么几百个,你吃透一个就少一个盲区,这套工程B卷的很多选择题,如果你做过其他大厂的真题,会发现考点是高度重合的。
在实际操作中我还发现一个容易被忽视的点:笔试环境。很多笔试用的是牛客网或者赛码网,代码编辑器没有自动补全,缩进可能也有问题,如果你平时在IDE里写代码习惯了,突然换到这种环境会非常不习惯。所以考前一定要去牛客网刷几套模拟卷,熟悉ACM模式的代码输入输出,适应限时环境,练习使用日志输出调试。这个准备往往比多背几道面试题更值钱。
最后再说一个跟考题无关但很关键的事情:时间安排。秋招笔试通常集中在晚上或周末,如果你白天还有实习,晚上状态可能会很差。我的经验是,提前一周调整作息,考试当天少喝咖啡,确保大脑供血充足。这种细节说起来简单,但对答题稳定性影响很大。
快手2019年秋季那套工程B试卷,放到今天看,依然是一套结构非常典型的工程校招笔试题。它的价值不在于让你背下具体某道题的答案,而是帮你建立一套应对大厂笔试的方法论:基础扎实、算法熟练、设计有逻辑、考试有节奏。希望对正在准备笔试的同学有实质性的帮助。