ARTICLE DETAIL

资讯详情

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

哔哩哔哩2020校招技术笔试复盘:算法与系统设计考点全解析

哔哩哔哩2020校招技术笔试复盘:算法与系统设计考点全解析 2020年我参加过哔哩哔哩技术岗的校招笔试二卷给我留下的印象比一卷深很多。这套卷子不是单纯筛知识量而是在限时压力下看你能不能把基础问题答得干净、写得清楚。很多人以为校招笔试是玄学其实它的命题脉络非常明确算法题拉区分度基础题看稳定性设计题看全局观。对准备投B站后端、客户端、算法岗的同学来说这套卷子的参考价值并不只是“刷一遍题”而是帮你理解技术笔试到底在筛选什么样的人。这篇文章我会按当年的命题方向做一次完整复盘拆解每个模块的考点、答题思路和容易踩的坑。不管你是正在准备校招还是刚接触技术面试都可以把这套题当成一份“体检清单”先测出自己哪里薄弱再针对性补。1. 哔哩哔哩2020校园招聘技术类笔试卷二命题思路复盘1.1 试卷整体结构与考查目标这套卷子并不是纯算法题集整体分成四个部分选择题/多选题、简答题、编程题、系统设计题。四个部分对应四种能力知识面、理解深度、代码执行力、方案设计能力。从公司视角看校招候选人的项目经验普遍不深所以笔试必须用标准化的题目来建立统一评价线否则后续面试很难横向比较。第一部分选择题覆盖面很广计算机网络、操作系统、数据库、Linux、智力题都有可能出现。简答题更像“小论文”比如让你解释HashMap在并发场景下的问题、讲清楚TCP挥手过程、说说索引失效的场景。这类题目批改成本高但能看出候选人是否真的理解而不是死记结论。编程题一般两到三道覆盖数组、字符串、链表、动态规划、二叉树这些核心数据结构。系统设计题是最后的重头戏通常给你一个具体业务场景比如“设计一个弹幕系统”“设计一个视频推荐接口”要求你给出存储选型、接口定义、并发处理和容错方案。整体来看这套卷子不是为了难倒人而是筛掉基础不扎实、代码写不干净、遇到开放问题就发散失控的人。1.2 为什么这些知识点会成为高频考点说到底技术笔试考的不是“工作中最常用什么”而是“一个合格工程师必须具备什么”。B站业务的特点是视频、直播、弹幕、社区每块业务都绕不开高并发读写、实时消息推送、海量存储和敏感内容过滤。所以笔试试卷里必然会出现TCP、进程线程、索引、缓存、消息队列这些东西它们是理解这些业务的技术底座。另一个容易被忽略的点是笔试题目必须尽量客观可判。选择题和编程题能自动判分简答题和设计题则需要人工看所以比例上客观题会多一些。这意味着你的编程题答案要能通过测试用例不能只写“思路正确”选择题更要又快又准因为在限时环境下纠结一道不确定的题会挤占后面大题的时间。我经常跟学弟学妹说一句话校招笔试是“筛选器”不是“排行榜”。你不需要把所有题都做出来但需要让面试官看到你的基础分数稳定、算法题有清晰思路、设计题有结构化表达。这套卷子的二卷尤其明显难度曲线是抖动的有些选择题比编程题还绕如果没提前适应节奏很容易翻车。2. 算法与数据结构最拉分也是最容易突击的部分2.1 高频考点动态规划、二叉树、双指针与前缀和校招笔试题库再大核心出题范围其实很集中。动态规划考察的是“状态定义”和“转移方程”二叉树考的是递归思想和遍历框架双指针和前缀和则考“如何用空间换时间”或“如何减少不必要的重复扫描”。B站这套二卷里编程题基本没跳出这几个方向。以动态规划为例常见题目有爬楼梯、01背包、最长公共子序列、编辑距离。很多人不是不会写转移方程而是不知道“为什么定义这个状态”。我在复习时习惯把动态规划题拆成两步第一步定义“dp[i]代表什么”第二步思考“dp[i]怎么从dp[i-1]、dp[i-2]或者dp[i-1][j]推出来”。只要这两步清晰代码写起来就是填表难点通常在状态定义。二叉树部分层次遍历是高频中的高频。它可以用队列实现也可以递归记录深度。这里考察的不只是结果对不对还有边界条件空树怎么办节点值溢出怎么办有没有利用到“完全二叉树”或“二叉搜索树”的特性来优化我见过很多人会把判断二叉搜索树写错只比较左孩子和右孩子忘记了中序遍历后应当递增才是严谨做法。前缀和和双指针通常出现在数组类题目里。比如“给定一个无序数组求连续子数组和为k的个数”如果暴力枚举左右端点复杂度O(n^2)但用前缀和加哈希表可以降到O(n)。这类题在日常开发里也很有用比如统计某类事件在时间窗口内出现的频率本质就是前缀和的思路。2.2 一道典型编程题的完整思考过程连续子数组和为K我以这套卷子里很可能会出现的变体题为例给定整数数组nums和一个整数k请计算该数组中和为k的连续子数组的个数。看到题目的第一反应是枚举所有起点和终点把区间和累加出来判断是否等于k。这个做法能过样例但一旦题目说明n很大就会超时因为最坏情况下有O(n^2)个子数组。这时候要转换思路连续子数组的和等于前缀和数组中两个位置的差。定义pre[i]表示从第0个元素到第i个元素的和那么子数组nums[j..i]的和就是pre[i] - pre[j-1]。我们需要找的是有多少对(i, j-1)满足pre[i] - pre[j-1] k也就是pre[j-1] pre[i] - k。于是可以一边遍历数组一边用哈希表记录每个前缀和出现的次数再查询pre[i] - k在哈希表里出现了几次。public int subarraySum(int[] nums, int k) { MapInteger, Integer preSumCount new HashMap(); // 前缀和为0的出现一次代表“从开头到当前元素”的情况 preSumCount.put(0, 1); int pre 0; int count 0; for (int num : nums) { pre num; if (preSumCount.containsKey(pre - k)) { count preSumCount.get(pre - k); } preSumCount.put(pre, preSumCount.getOrDefault(pre, 0) 1); } return count; }这段代码的时间复杂度O(n)空间复杂度O(n)。为什么要把preSumCount.put(0, 1)放在最前面因为如果某个子数组恰好从第一个元素开始那么pre[i] - k 0哈希表里必须能查到0的计数。这个细节很典型很多人考试时挂在这里逻辑上想通了但代码没初始化导致样例没过。2.3 刷题之外的三个细节输入输出、边界条件和复杂度预估在线笔试和LeetCode最大的区别是有些平台需要自己处理输入输出不仅要把核心逻辑写对还要把Scanner和循环写对。我建议准备阶段就固定一套自己的输入输出模板比如Java用BufferedReader加StringTokenizerC用ios::sync_with_stdio(false)避免考试时现场想怎么写。边界条件也决定通过率。题目说“数组长度可能是0”那你的代码一开始就要判断题目说“节点值可以是负数”你排序时是否考虑了绝对值题目说“结果可能超过int范围”你要不要用long。这些细节看起来小但在一道题多个用例的判定机制下一个没处理就会导致整体通过率骤降。复杂度预估同样重要。看到数据范围是10^5就要知道O(n^2)大概率超时看到数据范围是100O(n^3)可能还能接受。很多笔试平台不会告诉你超时用例长什么样所以自己要有敏感度。我习惯在写代码前先估一下时间复杂度和空间复杂度再决定用什么算法而不是上来就写最暴力的解法。3. 计算机网络与操作系统基础题里的“送分题”和“陷阱题”3.1 计算机网络高频考点TCP、HTTP、UDP这套卷子的选择题和简答题里网络部分几乎必然会考TCP三次握手和四次挥手。不要只背“三次握手是SYN、SYNACK、ACK”要能回答“为什么要三次而不是两次”。核心原因是避免历史重复连接请求到达服务端后服务端误以为新连接建立白白分配资源。TIME_WAIT也是高频陷阱。主动关闭连接的一方会进入TIME_WAIT状态等待2MSL后再真正关闭。这个设计是为了保证最后一次ACK能被对方收到也为了让连接上的旧报文在网络中自然消失。面试官如果继续追问“什么是2MSL、为什么是2MSL”你最好能说出“因为网络中报文最大生存时间为MSL一来一回最多2MSL”。HTTP部分重点关注状态码和HTTP/2特性。301和302的区别、401和403的区别、500和502的区别这些是选择题常客。HTTP/2的多路复用、头部压缩、服务端推送在B站这类视频网站场景里很实用因为页面加载需要并行请求大量资源。如果笔试中问“为什么HTTP/2能解决队头阻塞”你要能提到它在一个TCP连接上并行传输多个流而不是简单说“更快了”。UDP和TCP对比也常考。TCP可靠、有序、面向连接UDP不可靠、无连接、开销低。弹幕、直播这类对实时性要求高但能容忍少量丢失的场景更适合用UDP或基于UDP的定制协议。这里不能只背区别要结合场景表达为什么选它这也能为后面的系统设计题预热。3.2 操作系统必背考点进程线程、死锁、虚拟内存操作系统在技术笔试里的地位被很多人低估了。选择题喜欢考进程状态切换、线程和进程的区别、死锁产生的必要条件、虚拟内存与页面置换算法。这些东西看似和日常工作无关却是排查线上问题的基础。比如多线程程序为什么会出现缓存一致性问题本质就是CPU缓存和内存模型的差异。死锁的四个必要条件互斥、持有并等待、不可剥夺、循环等待。笔试时不仅要知道这四点还要知道如何从这四个条件出发去“破坏”死锁。比如加锁顺序保持一致可以破坏循环等待用超时机制可以破坏不可剥夺条件。如果简答题让你“设计一个避免死锁的方案”这样回答比直接背概念要加分。虚拟内存相关的页面置换算法也要熟练掌握。FIFO、LRU、LFU重点理解LRU在Redis缓存淘汰中的实际应用。B站这类业务有很多缓存场景如果系统设计题里让你设计一个缓存模块你第一反应应该是用哈希表加双向链表实现LRU而不是直接说“用Redis”。能说清底层实现和能说出Redis命令体现的能力层级完全不同。3.3 场景化答法把网络和操作系统串起来笔试中真正拉开差距的不是单点知识背诵而是综合应用题。比如简答题里问“设计一个支持高并发的Web服务简要说明你如何考虑TCP连接、线程模型和内存”这就不是单纯考察某一节内容。我的答题框架是三个层面接入层、处理层、存储层。接入层考虑连接管理用epoll或I/O多路复用避免一个线程阻塞在一个连接上。处理层考虑线程池大小要平衡CPU密集型和I/O密集型任务I/O密集型可以设置更大线程数。存储层考虑缓存和数据库热点数据先用Redis挡一层避免数据库被打垮。这样答出来面试官看到的是“系统思维”而不是零散知识点。4. 数据库与SQL写对多表查询是基本盘4.1 SQL高频题型分组统计、排名、多表关联数据库部分在技术笔试中占比不低最常见的是给你两张表和一段需求让你写SQL。比如视频表video(video_id, up_id, play_count, title)用户表user(user_id, user_name)然后问“查询每个UP主播放量最高的前3个视频”。这种题看着简单但分组取TopN恰恰是很多人的盲区。低版本MySQL没有窗口函数只能用关联子查询或用户变量实现如果允许窗口函数可以直接用ROW_NUMBER() OVER(PARTITION BY up_id ORDER BY play_count DESC)。我在笔试时优先写标准SQL因为窗口函数是SQL标准兼容性较好阅卷人也容易看懂。关键在于先分清楚“按什么分组、组内按什么排序、取前几”再决定用ROW_NUMBER、RANK还是DENSE_RANK。还有个经典陷阱是“去重统计”。比如“统计每天活跃UP主数”一个UP主一天登录多次只能算一次。有些人在GROUP BY之后直接用COUNT(user_id)结果把重复登录次数也算进去了正确做法是COUNT(DISTINCT user_id)。这类题考验的不是SQL语法熟不熟而是你有没有仔细读题。4.2 索引、事务、隔离级别和慢查询排查索引题通常问“为什么使用B树而不是B树或哈希索引”。B树只有叶子节点存数据非叶子节点能存更多索引项树高更低磁盘IO更少而且叶子节点之间有指针连接适合范围查询。哈希索引适合等值查询但不适合范围查找所以InnoDB的默认索引结构是B树。事务部分要牢记ACID、四种隔离级别以及MySQL的默认隔离级别是REPEATABLE READ。为什么需要MVCC因为读写并发不能互相阻塞MVCC通过隐藏版本号和undo log实现多版本并发控制读操作读到快照数据写操作加锁提升并发度。笔试简答只要把MVCC解决的问题和基本原理说清就能得分。慢查询排查也是高频考点。EXPLAIN关键字要看type、key、rows这几个字段type从ALL到index到range再到ref说明查询扫描范围在缩小。如果发现ALL优先考虑是否该建索引如果发现明明建了索引但没走要检查是否在索引列上做了函数运算、隐式类型转换或模糊匹配以通配符开头。4.3 场景题排行榜和计数器的存储选型数据库经常会和Redis一起出现在场景题里。比如“B站视频需要展示播放量高峰期怎么处理”简单方案是每次播放都UPDATE一次数据库但热点视频会让数据库压力很大。更合理的方案是先用Redis的INCR做计数异步定期把计数刷到MySQL或在读写分离架构中把播放量写入消息队列再批量落库。我在笔试时碰到类似题目会从三个角度看一致性要求高不高、数据量级多大、能不能接受短暂延迟。播放量这种数据延迟几秒完全可接受所以Redis加异步落库是最合适的。如果是交易金额就不能这样做必须保证强一致。答题时把“选型依据”说清楚比堆一堆技术名词有用得多。5. 系统设计题开放题怎么答才有区分度5.1 答题框架需求、容量、接口、存储、优化系统设计题是笔试里最让新人头疼的部分因为答案不唯一拼的是结构化和大局观。我一般用五个步骤答题先明确功能需求和非功能需求再做容量估算然后定义核心接口接着做存储选型最后说性能优化。这套框架可以用在短链接、弹幕、Feed流、排行榜等各种题目上。以“设计一个短链接服务”为例。功能需求是长链接转短链接、访问短链接时302跳转、可设置过期时间。非功能需求是支持高并发读、可用性高、存储成本可控。容量估算可以这么算假设每天生成100万个短链接一年就是3.65亿条每条记录估算100字节一年存储约36GB规模并不大单机MySQL都可以扛住但要考虑并发。接口定义要包括生成短链接的POST接口和重定向的GET接口。存储设计方面短链接和长链接的映射可以存MySQL同时用Redis缓存热点映射。生成短链的方式可以用发号器也可以对长链接做Hash然后截断但要注意碰撞。回答时还要补充如果同一长链接重复提交是否返回同一个短链接这需要加唯一索引或提前查重。5.2 弹幕系统怎么设计才能体现高并发功底哔哩哔哩笔试中很可能会出现和自身业务强相关的设计题弹幕系统就是经典之一。这道题的难点在于写多读多、实时性要求高、历史弹幕要能回放、敏感词要过滤。存储层面弹幕消息先进入消息队列比如Kafka或RocketMQ后端消费者写入存储引擎。实时弹幕需要广播给在线用户适合用WebSocket长连接推送而不是让前端轮询。用户发送弹幕时网关做基础校验敏感词用DFA算法或开源组件过一遍再进入消息队列。历史弹幕回放可以直接查MySQL或按视频ID分片的NoSQL存储。这里可以提分片方案按videoId做分片键查询一个视频的弹幕时只会打到某一个分片避免全表扫描。为了防止单个超热视频打爆分片可以对热点视频做缓存把一段时间内的弹幕放在Redis的有序集合里按时间排序读取。这样的回答体现了“我理解分布式系统的基本手段”而不是只会说“用Redis”。5.3 开放题最容易犯的三个错误第一个错误是只写方案不写原因。系统设计题不是画画架构图就行每个选型都要有依据。比如“为什么用Redis”在弹幕系统里Redis提供了快速读写和有序集合满足实时回放的需求。第二个错误是忽略非功能需求。很多人上来就写表和接口忘记了高可用、一致性、性能指标。笔试阅卷人很希望看到“接口响应时间目标是多少”“可用性目标是多少”虽然不一定算得很精确但有这个意识就能拉开差距。第三个错误是过度设计。明明是半年内几千万数据的规模非要上几十台机器、搞全套微服务这在笔试里反而会减分。好的设计是“在当前规模下够用同时有明确的扩容路径”。我通常会加一句“如果数据量增长到X我会把这一步替换为Y”这样显得既务实又有前瞻性。6. 笔试现场的时间分配、答题顺序和实战避坑6.1 限时答题的优化策略校园招聘笔试通常时长90到120分钟题量包含选择题、简答、编程和设计题。我建议拿到卷子后先用一到两分钟把全部题目扫一遍标出会做、犹豫、完全没思路三类。先把会做的做完尤其是选择题和简单编程题保证基础分到手再去啃难题。不要在一道选择题上卡三分钟蒙一个标记后面回来看都比空着强。编程题的时间分配要克制。一道题最多花二十分钟到半小时如果十分钟还没思路基本说明你当前水平或状态不适合死磕。可以先写下暴力解拿到部分用例分数再尝试优化。很多笔试平台按用例通过率给分零分和六十分之间差的就是“先写一个朴素实现”的勇气。简答题和系统设计题需要注意格式。分点作答、小标题清晰、逻辑连贯比写一大段话更受阅卷人欢迎。我记得有些同学明明知道答案但因为排版混乱面试官找不到得分点非常可惜。6.2 在线笔试平台常见故障与应对在线笔试最大的坑是本地运行正常、平台编译报错。原因通常是类名没改成Main、缺少import、JDK版本不同、输入输出格式不对。准备阶段就要用牛客、赛码等平台多练习惯它们的代码模板。考试时先确定代码入口函数名再开始写业务逻辑避免最后一秒发现类名不对。另一个常见问题是“没有读全题目”。题目里可能说“结果需要对1000000007取模”“数组下标从1开始”“允许重复选择元素”这些条件直接影响解法。很多人不是不会做而是看到熟悉的关键字就直接套模板结果连样例都没过。我习惯先看输入输出样例再倒推开题逻辑这样能快速验证理解是否一致。如果题目给出多个测试用例不要只验证一个。写完代码后在本地把边界情况测一遍空数组、只有一个元素、全负数、最大值边界。笔试平台往往不会告诉你哪一个用例挂了所以自己多用几个极端输入测发现溢出或数组越界马上修。这个小习惯能拯救你很多“看起来对但就是没分”的代码。6.3 从失败中复盘错题本比刷题量更重要笔试结束不是终点复盘才是提升的开始。我建议准备一份个人错题本每道题记录四个字段题目描述、我的错误答案、正确思路、错误原因归类。错误原因无非五类概念不熟、边界没考虑、复杂度估算错、代码语法错误、题目理解偏差。归类之后你会发现自己的薄弱点特别集中。我这套卷子复盘下来最大的收获是“系统设计题不能靠灵感”。你就算平时刷几百道算法题没练过设计题框架现场也容易越写越散。后来我把设计题的通用框架背到肌肉记忆不管题目怎么变先按需求、容量、接口、存储、优化五个维度展开至少能保证回答完整。另外要重视选择题里暴露出的基础盲区。很多人编程题写得不错却在网络和操作系统选择题上丢分这说明知识体系有死角。笔试前的最后两周与其继续刷难题不如把TCP状态图、进程状态切换、索引底层结构这些基础点再过一遍它们才是稳定拿分的压舱石。7. 高频问题排查表考场上看到这些情况怎么办现象可能原因处理建议编程题编译失败类名/方法名不符合平台要求切换到平台默认模板检查public static void main入口本地运行正确但提交0分输入输出格式不匹配用BufferedReader按行读取确认分隔符和输出格式结果溢出变成负数用int存大数改用long必要时对1e97取模死循环导致超时while循环条件漏了边界手动在纸上跑一遍循环确认一定会前进选择题两个选项都像正确概念混淆选择最贴合题干的项不要选绝对化表述设计题写不完过度追求完美先搭好框架每部分写三行关键点再填充细节简答题内容很少缺乏结构按“定义、原理、场景、优缺点”四个维度扩充这张表是我自己在多次模拟笔试中总结出来的很土但很实用。考试时遇到问题先深呼吸再对照这些常见场景找解药不要慌了神就乱改代码。再补充一个提醒有些题看起来考技术其实考情商和工程素养。比如题目问“线上服务CPU飙升你如何排查”你回答时不要只写top、jstack还要说先观察报警和变更记录、再确定是业务流量突增还是死循环。这种排查思路体现的不是命令多熟悉而是你面对线上事故时的冷静程度。8. 笔试之后从一张卷子到整个面试准备技术笔试只是校招的第一关但它的影响远不止这一场考试。你在这张卷子上暴露的问题大概率会在后续三到四轮面试里再次出现。算法题写得差面试手撕代码大概率也危险网络和操作系统基础不牢面试官随便深挖一句就可能露馅。所以我建议笔试结束后不管结果如何都要把每道错题当成一次“体检报告”。对于还在准备阶段的同学我想多啰嗦一句不要只盯着题库数量要注重基础体系的完整性。每天刷题之前花二十分钟过一遍计算机网络、操作系统、数据库的经典问题比盲目刷十道重复题型要有用得多。哔哩哔哩2020校园招聘技术类笔试卷二已经算是一套质量很高的模拟真题认真吃透它比零零散散做二十道普通习题收获更大。最后分享一个我的习惯每次笔试结束我会用十分钟在手机备忘录里写下三个问题——“我哪类题做得最差”“是知识盲区还是临场紧张”“下次考试我第一件事要做什么”。这几个问题看起来简单但连续记录五六场之后你会看到非常清晰的进步轨迹。希望这份复盘能帮你少走一些弯路在接下来的笔面试里把应有的水平稳定发挥出来。
返回列表