快手工程B卷笔试复盘:算法、基础与设计题全解析

快手工程B卷笔试复盘:算法、基础与设计题全解析 快手2019年春季校园招聘笔试试题--工程B试卷每年三四月份互联网大厂的春季补招和暑期实习招聘就会集中冒出来快手在这段时间的笔试一向以题量大、覆盖面广、考察细著称。我当年参加的是工程B卷整场做下来最大的感受是它不跟你玩虚的不考脑筋急转弯式的偏题怪题而是在基础功底上反复试探你的深度并且非常强调与真实业务场景的结合。如果你是准备投递快手工程类岗位的同学或者正在备战其他大厂校招笔试这篇复盘应该能帮你少走不少弯路。工程B卷这份试卷适合谁参考两类人一类是即将参加快手或同类互联网公司校园招聘笔试的应届生另一类是工作几年想回头补基础、检验自己技术功底的工程师。它的价值不在于题目本身有多难而在于它非常典型地反映了大厂校招笔试的出题逻辑——算法题占大头但计算机基础网络、操作系统、数据库绝不是走过场而业务场景题更是直接把你会不会写代码提升到你会不会用代码解决问题的层面。先说整场笔试下来我最直观的三个感受第一时间紧。两个小时的笔试算法题加上基础选择题如果你对某个知识点没有形成“肌肉记忆”级的熟练度很容易在某道题上卡住然后就乱了节奏。第二考点密度高。一份试卷里几乎把计算机核心课程过了一遍从C内存管理到TCP连接状态从数据库索引到分布式一致性甚至还会穿插一两道和短视频业务相关的场景设计题。第三场景化强。纯考记忆的题目不多很多题都会给一段业务背景——比如某活动页面短时间涌入大量请求用户上传视频后需要做转码处理——然后让你在这个背景下分析问题、选择方案或写代码。这就要求你不是死记硬背知识点而是真正理解它背后的原理和应用边界。下面我按考卷的模块拆解方式把工程B卷的核心内容、解题思路和备考心得完整分享出来。1. 工程B卷整体结构与出题逻辑拆解1.1 试卷模块与分值分布工程B卷的题型结构大致分为三类不定项选择题、算法编程题、主观设计题。不定项选择题覆盖计算机网络、操作系统、数据库、C/Java基础、Linux常用命令等算法编程题一般是两道一道偏数据结构与常见算法另一道会结合业务场景主观设计题通常是最后一道考察系统设计或问题排查思路。从分值上看算法编程题和主观设计题占了大头选择题虽然单题分值不高但胜在知识点分散、容错率低一不小心就会连环错。我参加的那场选择题大概有20道左右两道编程题各占20分左右最后一道主观题大概15分到20分。这里有个值得注意的点快手工程B卷的选择题非常多选选错、漏选都不得分所以对知识点的掌握必须准确不能靠模糊记忆去猜。1.2 为什么叫工程B卷快手笔试一般分为A卷和B卷有时候还有C卷对应不同的岗位方向。工程B卷更偏向后端开发、基础架构、服务端研发这类方向所以试卷里会特别强调高并发、分布式、存储、缓存这些在大流量场景下绕不开的知识点。这跟快手的业务形态高度相关。快手是短视频平台日活用户过亿用户上传视频、刷推荐流、评论点赞每一个动作背后都是海量的请求和数据处理。作为后端工程师你写的每一行代码都可能被部署在成千上万台机器上承受极高的并发压力。所以笔试不会只考单纯的算法而是会把算法放到具体的业务场景里去考——比如如何在海量视频中找出播放量Top100这样的问题。1.3 官方考察点与真实岗位能力的关联如果你把整份试卷拆开来看会发现它考察的能力模型和实际工作中的工程能力非常吻合算法能力对应的是你对数据结构和基本算法的掌握程度这是解决一切技术问题的底层工具计算机基础对应的是你在实际开发中能否理解程序运行的底层机制比如网络请求为什么慢、内存为什么涨、数据库为什么慢查询业务场景题对应的是你把技术方案落地到具体业务中的能力这决定你能否从写代码的人成长为解决问题的人。所以这份试卷本质上不是要难倒你而是想筛选出基础扎实、思路清晰、有业务Sense的候选人。2. 核心考点模块精讲每个知识点的考察方式与应对策略2.1 计算机网络不只是背协议更要会分析问题在工程B卷里计算机网络是选择题的重灾区也是很多人丢分的重灾区。考察的知识点基本集中在TCP/UDP、HTTP协议、TCP三次握手与四次挥手、流量控制与拥塞控制、DNS解析过程、常见HTTP状态码语义以及HTTPS的握手过程。你以为背下来就完了太天真了。我记得有一道题是这样的客户端与服务器建立TCP连接后客户端突然断电问服务器端会发生什么以及TCP的保活机制是如何工作的。这道题考的是你对TCP连接状态的理解深度——如果客户端断电服务器端不会立刻知道连接已断开它会一直维护着这条连接直到TCP的Keep-Alive定时器超时或者发送数据时收到RST报文。另一个容易翻车的地方是HTTP状态码。题目会给你一堆场景让你选对应的状态码——比如服务器无法理解请求格式是400请求的资源不存在是404而服务器内部错误是500。这些看起来很简单但一旦混淆了401和403的语义或者不知道408是请求超时就会丢分。我建议复习网络时不要只看协议本身要把为什么要这样设计搞清楚。比如TCP为什么要三次握手而不是两次因为要防止失效的连接请求突然又传到了服务器导致服务器建立无用连接。理解了这一点不管题目怎么变着花样考你都能抓住本质。2.2 操作系统进程线程、内存管理是永远的主旋律操作系统部分的考察重点非常清晰进程与线程的区别、进程间通信方式、线程同步机制互斥锁、信号量、条件变量、死锁产生的四个必要条件、虚拟内存与分页机制、页面置换算法、用户态与内核态的切换。有一道题我记得很清楚给出四个关于死锁的描述让你选出正确的选项其中涉及死锁的预防可以通过破坏互斥条件实现这个选项。这个选项是错的因为在大多数情况下互斥条件是无法破坏的——两个进程不可能同时使用同一台打印机所以实际工程中更多是通过破坏占有且等待不可抢占循环等待这三个条件之一来预防死锁。还有一个高频考点是虚拟内存。题目会给你一个系统配置物理内存大小、页表项大小、虚拟地址位数让你计算页表占用的内存大小。这种题看着复杂其实套公式就能解关键是要理解分页机制的原理而不是死记公式。我当时复习操作系统的策略是把每个知识点都和实际开发场景联系起来。比如进程间通信方式我就想到Redis的持久化是通过fork子进程来实现的Master进程和子进程之间通过管道通信多线程编程时为什么需要加锁我就想到ConcurrentHashMap在JDK 8前后锁粒度的变化。这样记起来既牢固又有趣。2.3 数据库索引与事务是必须拿下的基础题数据库部分的考点集中在MySQL上包括索引的数据结构B树、聚簇索引与非聚簇索引的区别、最左前缀匹配原则、事务的ACID特性、隔离级别、MVCC机制、以及常见SQL语句的编写。这里我要特别提醒一句不要只背概念一定要动手写SQL。工程B卷里大概率会有一道SQL编写题比如有两张表一张是用户表user(id, name)一张是订单表order(id, user_id, amount, create_time)请统计每个用户的订单总金额并筛选出总金额超过10000的用户题目本身不难考察的是基本的JOIN、GROUP BY和HAVING语法。让我比较意外的是有一道选择题考了B树和哈希索引的区别。题目问哪种索引支持范围查询答案是B树因为B树的叶子节点通过双向链表连接天然支持范围扫描而哈希索引适合等值查询一旦遇到范围查询就会退化为全表扫描。这道题虽然不难但它提醒了我一个事实面试官很看重你对底层数据结构特性的理解而不是仅仅知道MySQL有索引。还有一个容易被忽略的考点是事务隔离级别。可重复读Repeatable Read是MySQL默认的隔离级别它通过MVCC解决了不可重复读的问题但不能完全解决幻读——MySQL在可重复读级别下通过间隙锁Gap Lock部分解决了幻读。这个点如果不深入理解做题时就容易踩坑。2.4 C/Java基础内存管理与集合类是命题高发区工程类岗位的笔试通常要求你掌握C或者Java中的至少一门但不管选哪门内存管理和常用集合类都是必考的。如果你是C方向那么智能指针shared_ptr、unique_ptr、weak_ptr、内存泄漏的成因与排查、虚函数与多态的实现原理、STL容器的底层数据结构这些是必须吃透的。有一道选择题我记得是问vector扩容时旧元素是如何迁移的答案是分配一块新内存将旧元素拷贝或移动到新内存中然后释放旧内存。这个过程中如果元素的拷贝构造函数很耗时就会导致性能下降所以实际工程中会预先reserve足够的容量。如果你是Java方向那么HashMap的底层实现JDK 8中数组链表红黑树、ConcurrentHashMap的锁机制、JVM内存模型堆、栈、方法区、垃圾回收算法标记-清除、复制、标记-整理这些是高频考点。有一道题问JDK 8中HashMap在什么情况下会将链表转换为红黑树答案是链表长度超过阈值默认8并且数组长度大于等于64。这个细节很多人会忽略后半句导致选错。我个人的建议是复习时不要只背结论要把代码打开看看亲手在本地跑一跑观察一下不同操作下内存和性能的变化。比如写一个demo向HashMap中不断put元素通过debug观察链表什么时候变成红黑树这样记忆会深刻很多。2.5 Linux与常用命令那些不用背但必须会的知识工程B卷里还会出现几道Linux相关的选择题考察内容包括文件权限管理chmod、chown、进程管理ps、top、kill、文本处理grep、awk、sed、网络排查netstat、ping、traceroute、以及查看系统资源free、df、du等。这类题目的特点是不给你完整的命令而是给你一个具体需求让你选择合适的命令组合。比如如何查看某个进程监听的端口号正确做法是使用netstat -tlnp | grep 进程名或者使用lsof -i:端口号。如果你只记得netstat但不知道怎么过滤就会选错。这里有一个实战经验可以分享准备笔试时不用专门去背命令的每一个参数但你一定要用Linux环境动手敲一遍。我当时在本地装了一个Ubuntu虚拟机每天花20分钟练习常用的Linux命令特别是把awk和sed的常见用法过了几遍。笔试中看到这类题目时基本就是送分题。3. 算法编程题实战复盘从题目到AC的完整推导3.1 题目一滑动窗口内的最大值这道题是所有刷过LeetCode的同学都很熟悉的经典题——给定一个整数数组和一个滑动窗口大小k求每个窗口内的最大值。LeetCode 239原题难度Hard但只要掌握了单调队列的解法其实不难。我当时选择的实现方式是维护一个双端队列deque队列中存储的是数组下标并且保证队列中下标对应的值是单调递减的。每次窗口滑动时先将队尾所有小于当前元素的下标弹出再将当前元素下标压入队尾同时如果队首下标已经不在当前窗口内则将其从队首弹出。这样队首始终是当前窗口的最大值。时间复杂度O(n)空间复杂度O(k)。我在笔试现场大概是花了两分钟理清思路十分钟写完代码然后花了三分钟检查边界情况——比如k为1、k等于数组长度、数组为空这些特殊情况。这道题表面考的是数据结构的应用实际上考的是你对单调性这个核心思想的理解。我当时在注释里写了一段话单调队列的核心在于维护一个对后续计算仍有价值的候选集合元素之间的比较关系一旦确定就不会被重复比较从而把时间复杂度优化到O(n)。这个思想在很多算法题里都能用到。3.2 题目二求数组中的Top K个高频元素这道题是典型的海量数据 频率统计 Top K组合拳。题目给一个整数数组和一个整数k要求返回数组中出现频率最高的k个元素。第一反应是用哈希表统计每个元素出现的频率然后用堆来维护当前频率最高的k个元素。这里有个容量选择的细节维护的是一个大小为k的最小堆每次新元素进来时如果堆的大小小于k直接入堆否则比较新元素的频率和堆顶元素的频率如果更大就先弹出堆顶再压入新元素。这里还有一个更优的解法如果数组元素的范围很大用哈希表统计频率的空间复杂度是O(n)这个基本免不掉但求TopK的部分可以用快速选择Quick Select算法做到平均O(n)的时间复杂度替代O(n log k)的堆解法。笔试时我选择用堆因为代码更稳妥不容易出错——笔试求稳面试再求炫技。我做完这道题后的一个体会是TopK问题是大厂笔试的高频考题它的变体非常多比如从海量日志中找出访问次数最多的IP从100亿个整数中找出最大的100个数等。解题思路是通用的先用哈希表或计数法做频率统计再用堆或快速选择取TopK。把这个套路练熟遇到这类题基本就有了底。3.3 算法复习的推荐路线如果你现在才开始准备我建议你不要盲目刷题而是按照下面的优先级顺序来复习时间充足两个月以上LeetCode高频题100-200道按专题分类刷优先搞定数组、链表、二叉树、哈希表、双指针、滑动窗口、动态规划、DFS/BFS、单调栈、并查集。每道题做完后一定要看题解对比自己的解法和最优解法的差距思考为什么别人的解法更优。时间紧张一个月到两个月针对大厂笔试的高频题型专项突破尤其是数组/字符串处理、链表操作、二叉树遍历、TopK问题、LRU缓存、以及各种排序算法的变体。时间非常紧张两周以内只刷高频题和经典题每天保持2-3道编程题的节奏重点保证熟练度而不是广度。4. 主观设计题如何组织思路拿高分4.1 设计一个短网址系统工程B卷的主观题我记得很清楚是让设计一个短网址系统要求说明完整的系统设计思路包括API设计、存储选型、重定向流程、以及如何应对高并发。这种题目没有标准答案但它有明确的评分维度思路是否清晰、方案是否可行、是否考虑到了实际工程中的关键问题如并发、扩展性、缓存、数据持久化等。短网址系统的核心流程是用户提交长URL系统生成一个短URL并存储在数据库中用户访问短URL时系统根据短URL的标识查询到原始长URL然后返回302重定向。为什么用302而不是301这是一个经典的考点。301是永久重定向浏览器会缓存重定向结果后续访问短URL时直接跳到长URL不再请求短网址服务。这虽然可以减轻服务器压力但你无法统计短URL的点击次数302是临时重定向每次访问都会经过短网址服务虽然服务器压力大一些但可以做点击统计和分析。对于业务方来说点击数据分析是核心需求所以一般选中方案302。这个细节不一定会直接考但在设计题里主动提到能体现你的思考深度。存储选型上我当时的方案是使用MySQL存储映射关系同时用Redis做热点短URL的缓存。短URL的标识可以通过自增ID进行base62编码生成避免使用复杂的哈希算法——因为哈希会有碰撞问题而自增ID天然无碰撞。高并发方面需要考虑的是如果某个短URL被大量访问比如热点活动链接如何防止数据库被打爆做法是加Redis缓存并且设置合理的过期时间另外可以在应用层做限流比如使用令牌桶算法控制单个短URL的QPS上限。4.2 设计题的高分答题框架设计题一般都有固定的答题框架按照下面这四步走基本不会跑偏第一步明确需求。先搞清楚系统要解决什么问题核心功能有哪些非功能性需求是什么并发量、数据量、可用性要求。第二步做技术选型。根据需求选择合适的技术组件比如存储选SQL还是NoSQL、缓存选Redis还是Memcached、消息队列选Kafka还是RocketMQ并说明选择理由。第三步画出核心流程。说明数据是如何流转的从请求进入系统到返回响应的完整路径是什么每个环节的职责是什么。第四步考虑扩展性与容错。如果并发再翻十倍怎么办某个组件挂了怎么办有没有监控和告警日志怎么记录设计题最怕的就是没有结构、想到哪说到哪。我当时在脑内先搭了一个草稿框架然后按框架逐步展开最后还特意提到了缓存穿透、缓存雪崩的应对措施这应该是整道题的加分项。4.3 多拿分的小技巧主动补充分布式相关方案在做设计题时有一个小技巧非常实用在方案中主动提到分布式环境下的一致性、幂等性、负载均衡等问题的解决方案。比如短网址系统里你可以说当多个实例同时处理请求时需要保证短URL标识生成的唯一性因此可以采用预分配ID段或使用分布式发号器比如Snowflake算法来生成ID。这种回答方式有几个好处第一展示了你对分布式系统的理解第二证明了你不只是一个会写CRUD的码农而是一个有全局视野的工程师第三给面试官留下了充足的追问空间——后续面试中很大概率会顺着这道题继续深入你已经提前铺好了路。我在笔试中就把短URL的生成方案从数据库自增ID升级到了预分配ID段内存发号的方案解释了一下为什么自增ID在分布式场景下会成为瓶颈以及Snowflake算法的基本原理。写完这一段我自己都觉得整个方案的完整度上了一个台阶。5. 备考策略与时间分配建议5.1 考前一个月应该怎么规划如果你现在距离笔试还有一个月我建议把时间分成三个阶段基础复习期、刷题强化期、模拟实战期。基础复习期前两周每天上午复习计算机网络、操作系统、数据库中的一门下午刷算法题。复习方式以教材加博客为主重点是把核心概念吃透。我当时主要参考了《计算机网络自顶向下方法》《深入理解计算机系统》《高性能MySQL》这些经典书目的核心章节配合网上整理的高频面试题来巩固。刷题强化期中间一周算法题保持每天3-5道的节奏优先刷高频题。晚上集中整理错题本把每道题的解题思路、关键代码、易错点记录下来周末统一回顾。模拟实战期最后一周每天刷一套模拟卷或往年真题严格按照120分钟的时限来练习让自己适应考试的节奏和压力。同时把之前整理的基础知识点快速过一遍查漏补缺。5.2 各科目复习优先级排序我个人的经验是按下面的优先级来投入时间第一优先级算法与数据结构。这是笔试的得分大头也是最容易通过刷题快速提升的部分。建议每天至少保证2小时的刷题时间。第二优先级计算机网络与操作系统。这两门课的知识点相对固定多刷几遍高频考点就能较好地掌握性价比很高。第三优先级数据库与Linux。数据库的重点非常集中索引和事务搞懂基本就能应付大部分题目Linux命令则是熟练度问题多练就好。第四优先级编程语言基础。不要为了笔试去钻研语言的高级特性把内存管理、并发、常用集合类这些基础打牢就够了。5.3 笔试当天的应试技巧再分享几个笔试现场非常实用的技巧先把所有题目快速浏览一遍标记出自己擅长的题目先做会做的再啃硬骨头。不要在选择题上死磕太久遇到拿不准的可以先标记做完编程题再回头细想。编程题千万别留白。即使写不出来也要把思路写上去用伪代码描述你的算法有时候也会给一部分分。注意代码的边界情况处理。大厂笔试的判题系统对边界情况的测试非常严格数组越界、空指针、整数溢出都是常见扣分点。写在代码里的注释要清晰。虽然阅卷主要看判题结果但有些题目需要人工review清晰的注释和良好的代码风格会给你加分。6. 常见的丢分陷阱与避坑经验6.1 选择题里的绝对化陷阱很多选择题喜欢用一定必须所有任何这样的绝对化词汇这种选项往往是错误的。比如所有情况下二叉树的前序遍历结果都是唯一的——这个说法就是错的因为如果二叉树中有相同的元素值不同的二叉树结构可能产生相同的遍历序列。做题时养成一个习惯遇到绝对化表述先在脑子里找反例。找不到反例再选它能找到反例就果断排除。6.2 编程题中只追求AC的坑有些同学笔试时写代码只求通过题目给的测试用例忽视了代码的鲁棒性和复杂度。但大厂的测试用例往往非常全面包括边界条件、压力测试、极端输入等。我举一个例子题目要求求两个大整数之和如果你直接用int类型读入遇到超长整数就会溢出。正确的做法是用字符串处理逐位相加注意进位。这种细节在平时的刷题中就要养成习惯特别是要留意题目给出的数据范围。6.3 时间分配失衡的问题有不少同学在选择题上花了太多时间导致最后编程题只剩十几分钟写不完代码。我的建议是给选择题设定一个总时间上限比如50分钟到点必须停止无论有没有做完都要切换到编程题。编程题如果两道都很难也不要慌。先做相对简单的那道保证拿到一道完整的分再去尝试第二道。最忌讳的是跟一道难题死磕到底结果两道都没写出来。6.4 不要忽视手写代码的规范性笔试平台一般是牛客网或赛码网的在线编辑器没有IDE那么智能代码提示和报错提示都比较弱。我建议平时练习时就习惯在简单编辑器里写代码培养不看提示也能正确写出代码的能力。写字的时候要注意变量命名规范、缩进清晰、逻辑片段用空行隔开这样即使代码有bugreview时也更容易定位问题。6.5 关于模拟笔试的几点经验补充分享我在考前一周做了3次完整模拟每次都是严格按照2小时来计时。第一次模拟时我发现自己选择题做了50分钟完全给编程题留出了足够时间但第二次模拟时我故意加快选择题速度结果在几道多选题上连续失分。最后总结出来的经验是选择题不能一味求快宁可遇到不确定的先标记跳过也比瞎猜后心态崩掉好。另外如果你想在考试时避免坏习惯可以尝试在模拟时用同样的设备、同样的输入法因为有些考生在笔试现场会因为输入法切换问题浪费大量时间。7. 写在最后一点个人体会与实用建议笔试结束后我复盘整份试卷最大的感悟是快手工程B卷其实非常“务实”。它选的每一类题几乎都是从后端工程师日常工作中提炼出来的——你写的接口怎么应对高并发数据库索引怎么建才高效缓存用了什么数据结构服务之间的通信靠什么协议Linux机器上怎么用命令排查线上问题。几乎没有一道题是“为了难而难”它考的就是一个真实后端工程师的基本功。所以我特别建议还在准备阶段的同学不要只盯着算法题转多花点时间把自己的计算机基础打扎实多思考一下你写下的每一行代码在操作系统层面是怎么被执行的一次网络请求从发出到返回中间经历了什么一条SQL语句是如何在MySQL中完成优化和执行的。这些思考过程才是你应对各种变化的笔试题目最可靠的后盾。根据我个人实际参加快手春季校招笔试的经验来看笔试过了只是第一步它更像是叩开面试大门的敲门砖。但你为这份试卷付出的每一分努力梳理清楚的每一个知识点刷过的每一道题都会在面试的深度追问和今后的实际工作中以你想不到的方式回馈你。最后再分享一个小技巧做完笔试后一定要趁记忆清晰及时复盘把做错的题和不确定的选项对照答案整理到自己的错题本上——这份笔记在你冲刺下一场笔试或面试前的复习中价值巨大。