字节跳动2018后端校招笔试复盘:考点、编程题与备考路线

发布时间:2026/8/30 4:15:42
字节跳动2018后端校招笔试复盘:考点、编程题与备考路线 直接说结论字节跳动2018校招后端方向第四批这套题哪怕是放到今天依然是后端校招笔试的一个高性价比样本。我见过不少人拿着近两年的新题反复刷反而忽略了这类“旧题”里包含的稳定考点。2018年是字节跳动大规模扩招的年份校招笔试流程已经非常成熟第四批的题目在算法题难度、计算机基础覆盖面、考题风格上都很有代表性。对准备大厂后端校招的同学来说拆解这套题的价值不在于“押中原题”而在于搞清楚大厂到底用什么标准筛选候选人。这篇文章我会从考察模型、编程题复盘、基础考点梳理、面试延伸、学习路线、实战避坑这几个维度展开。不管你现在是大二开始系统准备还是秋招前临时抱佛脚只要你目标是大厂后端方向这篇文章都值得认真看完。1. 先搞懂这场笔试的考察模型1.1 笔试批次背后的招聘逻辑字节跳动的校招笔试是分批次进行的第四批意味着这已经是当季招聘中比较靠后的批次。很多人不理解为什么大厂要搞多批次笔试其实核心原因有两个。第一是简历流量太大。2018年字节跳动正处于业务高速扩张期后端岗位的简历投递量是普通公司无法想象的。多批次笔试本质上是把候选人分流到不同的时间窗口避免一次性笔试导致服务器过载也方便招聘团队分波段处理面试安排。第二是题库轮换需求。笔试题目不可能所有人用同一套否则泄题成本太低。分批次配合题库轮换能保证每批题目的公平性同时保持整体难度一致。所以第四批的题目在难度和考察维度上跟第一批、第二批不会有本质差异。字节出题组在设计校招笔试题时对“后端方向”有一套固定的能力模型算法与数据结构、计算机基础、工程思维。这三块在整张试卷中的占比是非常稳定的。1.2 后端方向笔试题型分布从我接触过的多批题目来看后端方向的笔试题型基本是“选择题 编程题”的组合。选择题覆盖计算机基础包括操作系统、计算机网络、数据库、Java语言特性等编程题一般是2到4道难度从LeetCode中等偏上到困难不等。题型的分布逻辑其实反映了大厂后端岗位的真实需求。选择题考查的是“你大学四年有没有认真上课”编程题考查的是“你拿到一个模糊问题能不能独立拆解并实现”。这两类能力在工作中的体现是完全不同的前者决定你的基本功下限后者决定你的上限。我当时整理过一个考点热力图在2018年字节后端多批题目中出现频率最高的是这么几类考点分类具体内容出现频率数据结构数组、链表、栈、队列、哈希表极高算法思想双指针、动态规划、贪心、二分查找高图论拓扑排序、最短路、并查集中等偏高字符串处理字符计数、模式匹配、重排高计算机基础进程线程、TCP/IP、数据库索引高语言特性HashMap原理、JVM内存、并发高这给我们的备考启示非常直接不要浪费时间在冷门算法上把高频考点练到肌肉记忆远比追求“题海战术”更有效。1.3 笔试筛选的真实标准这里我想说一个很多人没意识到的问题大厂笔试从来不是为了筛选“最优”而是为了筛选“达标”。后端校招笔试的淘汰率确实高但淘汰的并不是“不够聪明”的人而是“基本功不达标”的人。我见过太多候选人简历上写着熟悉Spring Boot、做过前后端分离项目但一上笔试连简单的字符串处理都写不利索。说实话这类人在工程实践中可能有潜力但在大厂的筛选逻辑里笔试是第一道闸门过不了就完全没有展示潜力的机会。所以对待这套题的态度应该是它是一面镜子照出你的短板在哪里。编程题AC不了说明算法功底需要补选择题错太多说明计算机基础有盲区。发现了问题才有针对性的补救方向。2. 三道代表性编程题的完整复盘这一部分我选了三道很有代表性的题目类型分别覆盖字符串处理、动态规划、图论拓扑排序。这三类题在2018年字节后端考题中出现频率很高而且它们的解题思路可以泛化到很多变体题目中。需要说明的是我下面给出的题目描述是根据当时题目的核心考点还原整理的不是一字不差的原题但考察点和难度级别是高度接近的。2.1 字符串重排构造字典序最小的回文串题目描述给定一个只包含小写字母的字符串判断能否通过重新排列其中的字符使其成为一个回文串。如果可以输出字典序最小的那个回文串如果不行输出空字符串。这道题看起来简单但实际AC率并不高。我见过不少候选人卡在“字典序最小”这个条件上说明大家对“可行性判断”和“构造方案”的拆解还不够熟练。回文串的必要条件是字符串中最多只有一个字符出现奇数次。这是判断可行性的核心。在确定可行之后构造字典序最小的回文串需要把字符分成两半左半部分按字母升序排列然后拼接反转的右半部分中间放那个出现奇数次的字符。public static String constructPalindrome(String s) { int[] count new int[26]; for (char c : s.toCharArray()) { count[c - a]; } int oddCount 0; char oddChar 0; for (int i 0; i 26; i) { if (count[i] % 2 1) { oddCount; oddChar (char) (a i); } } if (oddCount 1) { return ; } StringBuilder left new StringBuilder(); for (int i 0; i 26; i) { for (int j 0; j count[i] / 2; j) { left.append((char) (a i)); } } String leftStr left.toString(); String rightStr left.reverse().toString(); if (oddCount 1) { return leftStr oddChar rightStr; } return leftStr rightStr; }这道题有两个容易丢分的地方。第一是忘记处理奇数长度回文串的中间字符第二是构造右半部分时直接把左半部分反转而没有利用StringBuilder的reverse方法重新赋值。边界条件的处理能力就是靠这类细节练出来的。时间复杂度是O(n 26 * n/2)实际可以优化为O(n)空间复杂度O(1)。建议你在本地跑几个测试用例比如“aabb”应该输出“abba”“abc”应该输出空字符串。2.2 环形数组的最大子段和题目描述给定一个整数数组数组首尾相连形成一个环形数组。请找出其中连续子数组的最大和。子数组最少包含一个元素。这道题是经典问题“最大子段和”的环形进阶版。很多候选人能写出Kadane算法解决线性版本但一到环形就被绕晕了。这个考点非常典型因为它在原题基础上加了一层“情况分类”的思考。环形数组的最大子段和无非两种情况。第一种是最大子段不跨过首尾连接处这就是普通的最大子段和直接用Kadane算法解决。第二种是最大子段跨过了连接处这时等价于“数组总和减去最小子段和”。所以思路就是同时求出最大子段和与最小子段和取两者的较大值。public static int maxSubarraySumCircular(int[] nums) { int total 0; int maxSum Integer.MIN_VALUE; int curMax 0; int minSum Integer.MAX_VALUE; int curMin 0; for (int num : nums) { total num; curMax Math.max(curMax num, num); maxSum Math.max(maxSum, curMax); curMin Math.min(curMin num, num); minSum Math.min(minSum, curMin); } if (maxSum 0) { return maxSum; } return Math.max(maxSum, total - minSum); }这里有一个非常隐蔽的坑当数组中所有元素都是负数时total - minSum会等于0此时正确答案应该是最大子段和也就是那个最大的负数。所以代码里加了一个判断如果maxSum小于0就直接返回maxSum。这个细节我在批改别人的代码时经常看到有人踩坑。为什么因为“环形子数组的最大和”跟“非环形”的直觉不太一样很多人在套用total - minSum公式时忽略了全负数数组的特殊性。这就是笔试中区分候选人代码能力的关键点。2.3 依赖任务调度输出字典序最小的执行顺序题目描述现在有n个任务编号从0到n-1某些任务依赖于其他任务先完成。给定依赖关系如[a, b]表示任务a依赖任务b请输出一种可行的执行顺序。如果存在多种顺序输出字典序最小的那种。这道题考的是拓扑排序但加了一个“字典序最小”的约束这就把普通的BFS拓扑排序升级为“BFS 优先队列”的版本。依赖关系题的变体非常多比如课程表、编译依赖顺序、包管理器依赖解析本质上都是同一类问题。解题的核心思路是先统计每个任务的入度再把所有入度为0的任务加入优先队列。每次从优先队列中取出编号最小的任务加入结果集然后更新它指向的任务的入度。如果某个任务的入度变成0就把它加入优先队列。最后检查结果集大小是否等于n如果不等于说明存在环无法完成所有任务。public static ListInteger findOrder(int n, int[][] prerequisites) { ListListInteger graph new ArrayList(); int[] indegree new int[n]; for (int i 0; i n; i) { graph.add(new ArrayList()); } for (int[] edge : prerequisites) { int from edge[1]; int to edge[0]; graph.get(from).add(to); indegree[to]; } PriorityQueueInteger queue new PriorityQueue(); for (int i 0; i n; i) { if (indegree[i] 0) { queue.offer(i); } } ListInteger result new ArrayList(); while (!queue.isEmpty()) { int cur queue.poll(); result.add(cur); for (int next : graph.get(cur)) { indegree[next]--; if (indegree[next] 0) { queue.offer(next); } } } return result.size() n ? result : new ArrayList(); }这个代码看起来简洁但在面试和笔试中有几个容易被追问的点。第一个是为什么用优先队列而不是普通队列因为普通队列只能保证“可行”不能保证“字典序最小”。第二个是环的处理如果图里有环最终结果集大小一定小于n这个判断不能漏。第三个是图的存储方式邻接表比邻接矩阵省空间在n较大的时候是必须的选择。这道题如果换一种问法比如“输出所有可行的拓扑顺序”或者“判断是否存在唯一拓扑顺序”难度会瞬间上升一个层级但核心原理还是不变。建议你把这道题的模板吃透遇到变体能快速迁移。3. 笔试里的计算机基础高频考点命中率非常稳定3.1 操作系统进程线程与死锁后端笔试的操作系统题目不会考特别偏的理论核心集中在几个问题上进程和线程的区别、死锁产生的四个必要条件、虚拟内存的作用、用户态和内核态的切换。关于进程和线程很多人只会背“进程是资源分配的最小单位线程是CPU调度的最小单位”但笔试题目往往不会直接这么问它会给你一段具体的场景让你判断是进程间通信还是线程间通信或者问你多线程共享哪些资源、独占哪些资源。这时候光背概念是不够的你得理解进程的地址空间、文件描述符表、信号处理器是共享的而线程的栈、寄存器状态是独立的。死锁的四个必要条件——互斥、占有并等待、不可抢占、循环等待——几乎是必考题。笔试常见的出题方式是给一个资源分配场景让你判断是否可能发生死锁或者问你破坏哪个条件可以避免死锁。有一个我特别想提醒的点很多人把“循环等待”和“死锁”画等号这是不对的。循环等待是死锁的必要不充分条件死锁发生时必然存在循环等待但循环等待只是死锁的一个必要条件。理解这个区分选择题就能少错一道。3.2 计算机网络TCP握手挥手状态机网络方向的高频考点集中在TCP协议。三次握手、四次挥手、TIME_WAIT状态、TCP与UDP的区别、HTTP与HTTPS的区别这些是选择题的常客。三次握手和四次挥手的流程建议你在纸上画一遍状态迁移图而不是只看文字。画图的过程中你会自然理解为什么连接建立是三次而释放是四次——因为连接建立时服务器可以直接SYN和ACK一起发但连接释放时服务器收到FIN后可能还有数据要发送所以ACK和FIN不能合并需要分成两步。TIME_WAIT这个考点面试官特别喜欢考。TIME_WAIT出现在主动关闭连接的那一端持续时间为2MSL。为什么要等待2MSL一是为了保证最后一次ACK能到达对端如果ACK丢失对端会重发FIN二是为了让本连接的所有报文在网络中消失避免新连接收到旧连接的延迟报文。这两个原因笔试选择题和面试问答里都经常出现。HTTP和HTTPS的考点相对简单核心是HTTPS多了一层TLS/SSL握手解决了身份认证和传输加密的问题。注意一下HTTPS握手过程中的证书验证、对称加密和非对称加密的配合方式这块内容在选择题里的命中率也很高。3.3 数据库索引、事务隔离级别与MVCC数据库是后端笔试的重头戏索引和事务是两大核心。索引部分的常见选择题是为什么InnoDB使用B树而不是B树、红黑树、哈希表这个问题的标准答案是B树只有叶子节点存储数据非叶子节点可以存储更多索引键从而降低树高减少磁盘IO次数同时叶子节点通过双向链表连接适合范围查询。很多人还会背B树和哈希索引的区别哈希索引不支持范围查询不支持排序但有精确匹配时效率极高。事务隔离级别也是一个高频考点。读未提交、读已提交、可重复读、串行化这四种隔离级别分别解决了什么问题还遗留什么问题最好用表格对比记忆。这里有一个容易踩坑的点MySQL默认的隔离级别是可重复读不是读已提交。很多人记反了。MVCC的原理笔试可能不会考得太深但面试一定会问。核心是版本链和ReadView的机制多版本并发控制通过undo log保留数据的历史版本加上ReadView判断某个版本对当前事务是否可见实现了不加锁的读写并发。数据库这块如果完全没概念强烈建议找一篇讲InnoDB行格式和undo log的文章把底层的版本链画一遍。3.4 Java基础HashMap、JVM与并发后端笔试的语言特性题如果选的是Java方向HashMap原理是绝对的明星考点。HashMap的底层结构是数组加链表加红黑树扩容机制、哈希冲突处理、为什么阈值是8都是可能出题的点。关于为什么阈值是8官方注释给的说明是泊松分布下链表长度达到8的概率极低所以用8作为链表转红黑树的阈值。这个数字不是随便定的背后是概率统计的考量。虽然选择题大概率不会让你算这个概率但理解这个设计思路可以让你在面试中回答得更深入。JVM方向的高频考点是内存区域划分、垃圾回收算法、类加载过程。后端笔试主要考内存区域堆、虚拟机栈、本地方法栈、方法区、程序计数器每块区域存什么、线程共享还是私有、什么情况下会抛OOM都需要掌握。并发方向这里只强调一个最核心的点synchronized和ReentrantLock的区别以及volatile的可见性、有序性问题。字节的后端笔试题比较务实不会考太偏的并发工具类但synchronized的锁升级过程、volatile如何防止指令重排建议好好看。4. 笔试只是起点后面几轮面试怎么延伸4.1 字节后端校招的整体流程字节2018年校招的流程大致是网申、笔试、技术面试一般2到3轮、HR面试、offer审批。笔试通过后技术面试通常会在两周内安排每轮面试45分钟到1小时左右。笔试的部分我前面已经拆得很细了这里重点说笔试到面试的衔接。面试官手里是能看到你的笔试成绩的包括每道编程题的AC情况。这意味着面试官在面试中可能会针对笔试的薄弱点进行追问。比如你笔试中有一道动态规划题没AC面试官可能会在面试中出一道同类型的题目确认你是“这次没发挥好”还是“真的不会”。所以笔试结束后不要急着放松建议立刻复盘每道题的思路。如果当场没AC的题回去一定要把正确解法写一遍弄明白卡住的地方在哪。这个习惯不仅对字节有用对其他大厂同样适用。4.2 从笔试考点延伸出的高频面试题笔试题里考的是选择题和编程题但同样的知识点到了面试环节会升级为开放性问题。比如数据库索引笔试问的是“为什么用B树”面试就会问“给你一张千万级的表你怎么优化查询性能”。比如HashMap笔试问的是“HashMap的put流程”面试就会问“HashMap在并发场景下会有什么问题”。我整理了一张从笔试到面试的考点延伸对照表笔试考点面试延伸问题TCP三次握手如果第三次握手丢失会发生什么死锁必要条件写一个会发生死锁的代码段B树索引原理联合索引的最左前缀原则是什么HashMap原理ConcurrentHashMap如何保证线程安全进程线程区别进程间通信方式有哪些各自适用场景动态规划空间复杂度如何从O(n)降到O(1)拓扑排序如何判断一个图是否存在环建议你有针对性地准备这些延伸问题。笔试是“知道不知道”的测试面试是“理解不理解”的测试。4.3 场景设计题怎么答字节的技术面特别喜欢出场景设计题比如“设计一个短链接系统”、“设计一个排行榜”、“设计一个限流器”。这类题目没有标准答案面试官考察的是你的分析框架。场景设计题的核心是回答结构我建议按“功能拆分、存储设计、接口设计、扩展性考虑”四步走。功能拆分先确定系统要支持哪些核心功能存储设计选择数据库和缓存方案接口设计定义主要API扩展性考虑说明系统如何应对数据量增长。举个例子设计短链接系统功能拆分为生成短链接、跳转、统计访问量存储设计可以用基础表存储长链接和短码的映射配合缓存加速访问接口设计包括生成接口和跳转接口扩展性考虑是短码的生成策略、全局唯一ID的生成方式、读写分离等。按照这个框架答即使方案不完美面试官也能看到你的思路清晰。5. 刷完这套题后端学习路线怎么规划5.1 第一阶段算法和数据结构打底不管你是科班还是非科班算法和数据结构永远是后端岗位的第一道门槛。这个阶段的目标不是“刷完XXX题”而是把常见的数据结构和算法思想烂熟于心。我的建议是按分类刷题而不是按顺序刷题。先把数组、链表、栈、队列、哈希表这五类基础的练熟再进入二叉树、堆、图这些进阶结构。算法思想上双指针、二分、贪心、动态规划、回溯这五个思想是笔试的绝对高频。每一道题刷完之后复盘比刷题本身更重要。我当时的要求是每道题都要在三天后重新写一遍能独立AC才说明真正掌握了。如果没有这一步刷再多题也只是“看起来努力”。5.2 第二阶段计算机基础系统过一遍算法过关之后就要系统过一遍计算机基础。操作系统、计算机网络、数据库这三门课是后端笔试选择题的基本盘。这里我特别想强调“体系化”的重要性。很多人是零散地背知识点今天看一点TCP明天看一点索引结果到了笔试时知识点之间是散的遇到综合题就不知道怎么组织答案。正确做法是以面试题为线索把知识点串成体系。比如你看到一个进程和线程的题目不只是背定义而是顺着思考进程之间怎么通信线程之间怎么同步这些机制在Java里对应什么API底层是怎么实现的这样的学习方式虽然慢但每一轮学习都是在加固知识网络而不是零散地塞入碎片。5.3 第三阶段项目实战与框架理解笔试不太考框架知识但面试中一定会问项目。近几年的校招场景里前后端分离项目、Spring Boot Vue的组合已经成为标配而且很多同学会用若依框架这类开源的快速开发平台来做项目。对于项目这块我只有一条忠告不要为了“有项目”而做项目。面试官问到项目时的核心问题永远是“为什么这么设计”“你遇到了什么难点”“如果数据量翻十倍怎么办”。如果你的项目只是照着教程敲了一遍这些问题你根本答不上来。做项目时尽量去理解框架的运行原理。Spring Boot的自动配置、Spring IOC和AOP的核心机制、MyBatis的Mapper代理原理这些内容不会直接出现在笔试里但会在面试中成为区分你“会用框架”和“理解框架”的关键。5.4 时间分配建议阶段时长核心任务占比算法数据结构2-3个月按分类刷题分类总结40%计算机基础1-2个月操作系统/网络/数据库/Java基础30%项目与综合1-2个月项目复盘模拟面试30%这个时间比例是参考值基础好的人可以缩短第一阶段基础薄弱的建议原地夯实。6. 笔试现场的实战经验与避坑清单6.1 输入输出和OJ环境的坑笔试编程题环境通常是牛客网或赛码网这些平台对输入输出的处理要求和LeetCode完全不同。LeetCode帮你封装好了函数参数但牛客网需要你自己处理标准输入输出。这是一个非常低级但杀伤力巨大的坑。平时在LeetCode刷题只写核心函数到了笔试时可能连Scanner怎么用都手生了。我建议在笔试前一周专门用牛客网的环境刷几道题熟悉“多行输入解析”“循环读取直到EOF”“输出格式精确到空格”这些细节。另外一个常见的坑是Java主类名。有些平台要求主类名为Main如果你在本地习惯写类名为Test复制到平台后忘了改就直接编译错误。这类问题丢分极其可惜。6.2 时间分配策略编程题的做题时间我建议按“难度评估 优先保底”的策略来分配。拿到卷子后先把所有编程题通读一遍评估出每道题的难度然后从最简单的开始做。先确保能做出来的题都能AC再回头啃难题。这个策略的核心逻辑是笔试的通过标准不是“所有题都AC”而是“排名达到前面的比例”。A一道中等难度题加部分用例可能比死磕一道困难题AC不了更有价值。我在笔试现场见过太多人在一道题上死磕40分钟结果其他题连看都没看。6.3 容易丢分的小细节第一编程题先写思路再写代码。如果时间充裕在代码前面用注释写清整体思路方便阅卷系统评估也方便自己排查逻辑错误。第二变量命名要语义化不要用a、b、c这种无意义命名万一调试时看错变量名会浪费大量时间。第三注意数据范围如果数组长度到10的5次方O(n^2)的算法大概率会超时需要提前想清楚时间复杂度的上限。这些细节单看都不算大事但叠加起来可能就是“通过”和“不通过”的差距。6.4 常见问题速查表问题解决方案Scanner读取整行时遇到空行用hasNextLine判断避免NoSuchElementException整数溢出涉及累加的字段用long最终输出再转回int递归层数过深导致栈溢出改写为迭代或增大栈内存优先队列排序不符合预期自定义Comparator明确排序规则链表类题目出现空指针统一处理head为空的情况先画图再写代码反复超时检查是否有重复计算考虑用哈希缓存中间结果编译环境不支持某些语法用Java 8兼容写法避免使用过新的语法特性写到这里我想分享一个比较个人的体会。当年我自己准备校招的时候笔试前最焦虑的不是算法题不会做而是“不知道大厂到底想考什么”。后来拿到多套大厂的笔试题目放在一起对比才发现考点高度重叠只是换了一层包装。字节2018校招后端方向第四批这套题就是一个很典型的坐标系算法题考的是你拆解问题的能力基础题考的是你大学四年有没有认真积累而面试考的是你把这些知识串起来的能力。所以你现在不管处于哪个阶段拿这套题当镜子照一下自己哪里薄弱就补哪里。我一直觉得校招备考最忌“漫无目的地努力”确定方向后持续投入效果好过盲刷几百道题。最后再分享一个小技巧每道你做错的笔试题不要只看正确答案要写一行“我为什么错”的注释。这个习惯我保持了很久后期复盘时价值极大。

相关新闻