第四范式后端笔试复盘:数组指针、Linux与Java并发考点全解析
发布时间:2026/9/1 22:02:57 作者:尧图编辑部 阅读量:1,286

2020年秋招我投了第四范式的后端研发岗。笔试是在线上平台完成的限时90分钟题量不算夸张但信息密度很高。当时我已经刷了不少大厂真题自认为算法底子够用真正坐到考场上才发现AI平台公司的后端笔试题和纯互联网公司不是一个路数。它不太爱出偏题怪题而是把基本功的深度理解放在第一位——数组和指针的关系、Linux内核的工作机制、Java并发和JVM、SQL索引优化基本覆盖了后端日常开发的全部核心场景。这篇文章把那次笔试的题型分布、我当时的答题思路以及事后复盘总结的备考经验完整拆开来讲供准备这类AI公司后端岗的朋友参考。1. 拆卷子2020秋招第四范式后端笔试的总体构图1.1 试卷结构与时间分配先说整体印象。这套卷子分四个板块单选、多选、编程题和简答题总分100分考试时间90分钟。我记忆里比较清晰的题型分布大概是这样的板块题量分值占比考察方向单选题10题左右20%数据结构、OS基础、Java语法多选题5题左右15%概念辨析、易混知识点编程题2-3题40%算法与数据结构实现简答题3题左右25%Linux、数据库、场景设计这个配比很典型。单选多选考的是你知不知道编程题考的是你会不会用简答题考的是你理不理解背后的原理。相比某些互联网大厂直接上5道算法题的做法第四范式的卷子明显更看重基础概念的扎实程度尤其对C/C的指针、内存这类底层知识盯得很紧。时间分配上我当时的策略是先花15分钟把单选多选快速过一遍拿不准的先标记跳过然后全力做编程题最后留25分钟写简答题和回查。90分钟的限时其实不太宽裕编程题如果第一题卡住超过20分钟后面就会很被动。1.2 与互联网大厂后端题的差异点对比我同期做的其他公司笔试第四范式这套题有几个明显的差异。第一底层知识的占比更高。互联网大厂的卷子有时候算法题可以撑起大半边天但这套题里C语言指针、内存布局、系统调用这类题目占了不小的比例。背后原因不难理解第四范式的核心业务是AI平台和企业级智能决策系统后端要直面高并发推理服务、分布式训练调度、模型生命周期管理这类场景底层功底不扎实的人是扛不住的。第二场景题更贴近AI平台这个业务属性。简答题里出现过的场景比如线上推理服务出现CPU飙升如何排查模型特征存储的缓存策略怎么设计都明显带着AI基础设施的色彩。这不是随便背几道八股文就能应付的需要对真实生产环境有感觉。第三多选题的迷惑性很强。它不考冷门知识专考那些你以为会但其实没吃透的点。比如进程和线程的区别、TCP三次握手的状态变化、HashMap在并发下的行为每个选项看起来都像是对的但总有那么一两个藏在细节里的坑。2. 数组和指针C/C基本功题的连环坑2.1 指针与数组的关系一道送命题的完整推导这套卷子的选择题里数组和指针相关的题至少出现了两道这也正好对应热搜词里数组和指针笔试题的高频度。先看一个非常经典的变体我当时在考场上是这么推的#include stdio.h int main() { int a[5] {1, 2, 3, 4, 5}; int *p a; printf(%d\n, sizeof(a)); // 输出多少 printf(%d\n, sizeof(p)); // 输出多少 printf(%d\n, *(a 1)); // 输出多少 printf(%d\n, *(a 1) - 1); // 输出多少真正取到的是哪个值 return 0; }第一个空sizeof(a)在32位系统下是20在64位系统下还是20因为a是一个完整的数组类型int[5]sizeof作用于数组名时取的是整个数组占用的字节数5个int乘以4字节等于20。第二个空sizeof(p)就不一样了p是指针变量在64位系统下固定是8字节。这里的关键在于数组名在大多数表达式中会退化成指向首元素的指针但在sizeof和取地址这两种语境下不会退化。第三个空*(a 1)是2这没什么好说的指针偏移一个int单位。第四个空是真正的陷阱。a取的是整个数组的地址类型是int(*)[5]对它加1意味着跨越整个数组指向数组末尾之后的位置。所以*(a 1)在数值上等于a 5再减1就回到了a[4]结果是5。这个推导过程看起来简单但考场上容易在a 1这一步翻车。很多人把a和a当成一回事写出*(a 1) - 1的答案那结果就变成1了。要记住a和a的数值相同但类型不同步长也不同。2.2 边界条件与内存布局答题时最容易翻车的地方数组和指针类题目失分最多的地方其实不在概念本身而在边界条件和内存布局的理解上。单选题里有一道类似的题问的是下面这段代码的访问结果int func(int *arr, int len) { int sum 0; for (int i 0; i len; i) { // 注意这里是 sum arr[i]; } return sum; } int main() { int arr[4] {1, 2, 3, 4}; printf(%d\n, func(arr, 4)); return 0; }这题的考点是off-by-one错误。循环条件i len意味着i会从0跑到4访问arr[4]而数组的合法下标是0到3。arr[4]在C语言里是未定义行为在堆栈布局中它恰好读到了相邻内存位置的值——可能是main函数的栈帧数据也可能是其他局部变量。答案不是固定的但从出题角度来说它要考察的是你能不能识别出这个越界访问。我在复盘时总结了数组和指针题的几个高频失分点数组名退化时机sizeof、、字符串初始化三种场景不退化其余大多数情况退化为指针。指针步长int *加1跳4字节char *加1跳1字节结构体指针加1跳整个结构体大小。多维数组的连续性int a[3][4]在内存中是一段连续的12个int空间a[1]是第二行的首地址a[1][0]和a[1]数值相同。函数传参函数参数中的数组一律退化为指针void f(int a[])和void f(int *a)完全等价。这些点单独拿出来都不难但它们组合出现在一道多选题里迷惑性就上来了。我的建议是把常见坑整理成一张表考前过一遍比盲目刷题效率高得多。3. 算法编程题从暴力解到最优解的思维路径3.1 高频题型TopK、区间合并与字符串处理编程题是这套卷子的重头戏两道题加起来占了40分。我根据当年考场上遇到的题型和社区里同期同学的回忆整理出三个最高频的方向TopK问题、区间合并、字符串处理。这三个方向在第四范式这类AI公司的笔试中反复出现因为它们在工程中确实用得上——推荐系统的特征筛选、日志聚合、请求参数解析本质都是这些问题。先看TopK。题目一般长这样给定一个包含n个整数的无序数组找出其中最大的K个数要求时间复杂度尽可能低。第一反应是排序O(n log n)的复杂度能得分但不够好。进一步想到用大小为K的小根堆遍历数组时如果当前元素比堆顶大就替换堆顶并调整堆时间复杂度O(n log K)已经不错了。如果K远小于n还能用快速选择QuickSelect做到平均O(n)。我当时写的是小根堆解法因为实现简单、不容易出错而且面试官问起来也能讲清楚堆调整的过程。核心思路 1. 维护一个大小为K的小根堆 2. 遍历数组若元素大于堆顶弹出堆顶并插入新元素 3. 堆中剩下的就是最大的K个数区间合并也很经典。题目通常是给出一组可能重叠的区间要求合并所有重叠区间后输出。比如[[1,3],[2,6],[8,10],[15,18]]合并后是[[1,6],[8,10],[15,18]]。解法思路是先按区间起点排序然后遍历。用两个变量维护当前合并区间的左右端点如果下一个区间的起点小于等于当前右端点就扩展右端点否则把当前区间加入结果并开始新的合并。这个题考的是模拟能力和对排序的理解难度不大但要注意输入为空、区间只有一个、区间完全包含等边界情况。3.2 复杂度分析怎么写在试卷上才加分笔试的编程题和面试手写代码不一样没人听你口述思路你只能在代码注释里或者简答题区域展示你的思考过程。我当时的经验是在代码开头用注释写明算法思路和复杂度分析这是个加分项。比如TopK的小根堆解法我会在注释里写// 思路维护大小为K的小根堆堆顶为当前K个最大数中的最小值 // 遍历每个元素若比堆顶大则替换堆调整O(logK) // 时间复杂度O(nlogK)空间复杂度O(K)不要小看这几行注释。阅卷人每天批大量卷子一份代码能不能快速看懂注释很关键。更重要的是注释能证明你不只是写出了代码还知道自己在干什么。很多同学代码能跑通但问他复杂度直接懵这就是平时刷题只追求AC不追求理解的后遗症。编程题还有一个容易忽略的点输入输出格式。在线笔试平台对输入输出的要求很严格比如多个测试用例逐行读入、每个结果换行输出这些细节错了即使算法正确也是0分。我建议平时练习就养成用标准输入输出写题的习惯不要依赖IDE的调试工具。4. Linux与操作系统命令行之外的内核理解4.1 进程线程与调度这些概念题背后的运行逻辑简答题里有一道关于进程和线程的问的是两者的区别以及在实际服务中如何选择。这类题目考得太多以至于很多人觉得已经是背烂了的八股文。但2020年的这道题换了个问法不是让你列区别而是给出一个高并发服务的场景问你为什么用线程池而不是直接创建线程。这个问法把死记硬背的东西变成了需要理解的内容。线程比进程轻量主要因为同一进程内的线程共享地址空间、文件描述符等资源创建和切换时不需要重建页表内核态的上下文切换成本更低。但共享地址空间也意味着一个线程的非法内存访问可能拖垮整个进程所以线程安全、锁竞争、死锁这些话题才那么重要。调度相关的题也值得多说两句。选择题里考过CFS完全公平调度器的基本思路Linux通过虚拟运行时间来保证每个进程都能公平地获得CPU时间。实际开发中不太会直接修改调度器但理解时间片、优先级、IO密集型和CPU密集型任务的区别对排查线上问题很有帮助。比如一台机器CPU使用率很低但服务响应很慢很可能不是CPU不够而是线程大量阻塞在IO等待上。这时候用top看到的是大量%waIO wait高企而不是%ususer space高企。这就是概念落到实践上的价值。4.2 内存管理与IO模型答出关键字的进阶姿势Linux相关的选择题里有几道关于内存管理的比如虚拟内存、页表、缺页中断、swap。这些都是操作系统课程的核心概念但笔试题目往往会结合一段free命令的输出让你判断系统的真实内存状态。# free -m total used free shared buff/cache available Mem: 15947 12437 802 187 2707 2623 Swap: 8191 1024 7167一个常见的问题是used和available的区别是什么如果套概念used是已使用的内存available是可用的内存。但深入一层available计算的是在不触发swap的情况下还能分配给新进程的内存它会把可回收的cache算进去。所以即使free列显示只有802MB系统也未必缺内存因为buff/cache在内存压力大时是可以回收的。IO模型是另一个高频考点。第四范式的简答题里出现过epoll和select的区别。这道题问得很细不是让你说epoll性能好就完事而是要讲清楚为什么。select的fd集合有上限通常是1024每次调用都要把fd集合从用户态拷贝到内核态内核态轮询所有fd返回时还要再拷贝一次。epoll使用事件驱动机制通过epoll_ctl注册fd内核只返回就绪的fd列表不存在遍历全部fd的开销支持的并发连接数远超过select。面试官想听到的关键点是select是轮询两次拷贝epoll是事件回调零拷贝就绪列表。这个概念搞清楚了不管题目怎么换姿势问都能答。实际工程中Nginx、Redis的高并发模型都建立在epoll之上理解了它再去读这些中间件的源码会顺畅很多。5. Java与数据库后端研发的必考肌肉记忆5.1 Java集合与并发从源码层面回答为什么第四范式的后端岗位以Java为主所以Java相关的选择题和简答题一定是重头戏。我印象最深的是多选题里关于HashMap和Hashtable区别的一道题以及一道关于ConcurrentHashMap在JDK 1.8中如何保证线程安全的简答。先说HashMap的底层原理。JDK 1.8的HashMap是数组链表红黑树的结构数组每个位置是一个桶发生哈希冲突时用链表存储当链表长度超过8且数组长度超过64时链表转为红黑树。很多人背了这个结论但笔试问得更细为什么转红黑树的阈值是8这个8不是随便定的。根据泊松分布的计算在负载因子0.75、哈希函数分布均匀的前提下一个桶中链表长度达到8的概率大约是千万分之一。也就是说正常情况下链表长度根本到不了8就扩容了如果真的出现长度为8的链表说明哈希函数有严重问题或者发生了一定程度的哈希碰撞攻击。这个数字是空间和时间的权衡结果。并发相关的题目里volatile和synchronized的区别、CAS的原理、AQS的设计都是高频考点。比如简答题问volatile能保证原子性吗标准回答是volatile保证可见性和有序性但不保证原子性。i这种复合操作即使变量声明为volatile多个线程同时执行时依然会产生数据竞争因为读取-修改-写入三步不是原子的。ConcurrentHashMap在JDK 1.8中的实现方式也值得细说。1.8版本放弃了分段锁改用CAS synchronized对数组中的每个桶加锁。具体逻辑是如果桶位为空用CAS直接插入新节点不需要加锁如果桶位不为空才用synchronized锁住桶首节点再执行插入或替换。这样做的好处是并发度从固定的16个分段提升到数组长度级别而且锁粒度更细。5.2 SQL优化与索引一条慢查询的完整排查思路数据库相关的考题集中在MySQL上索引设计、SQL优化、事务隔离级别是三个最常见的方向。这套卷子的简答题里有一道SQL优化题给出一条执行很慢的查询语句要求分析原因并给出优化方案。题目大概是这样的SELECT * FROM orders WHERE user_id 12345 AND create_time 2020-01-01 ORDER BY create_time DESC LIMIT 10;这条SQL慢核心原因很可能是索引设计不合理。如果只在user_id上建立了单列索引MySQL可以先通过user_id 12345过滤出一批订单但create_time的排序没法走索引需要临时文件排序filesort订单量大时性能就崩了。优化方案有两个方向。第一建立联合索引(user_id, create_time)这样既能过滤user_id又能让create_time的排序直接走索引避免filesort。第二如果查询的结果集很大且只需要部分字段把SELECT *改成只查询需要的列减少回表次数。比如只需要订单号和金额那么建立(user_id, create_time, order_id, amount)的覆盖索引效果更好。索引的最左前缀原则也是必考内容。联合索引(a, b, c)能用到索引的查询条件组合有a、a,b、a,b,c三种如果查询条件里没有a比如只写了b 1那这个联合索引就用不上。这个知识点不光笔试考实际工作中设计索引时也天天要用。Redis相关的题也出现过。缓存穿透、缓存击穿、缓存雪崩这三个概念在AI平台的后端场景里尤其重要。模型特征数据往往是热点数据缓存策略设计不好一次特征更新就可能打爆后端存储。我当时回答的思路是缓存穿透查询一个不存在的key请求直接打到数据库。解决缓存空值并设置短过期时间或使用布隆过滤器拦截。缓存击穿某个热点key过期瞬间大量请求同时打到数据库。解决互斥锁重建缓存或设置逻辑过期时间。缓存雪崩大量key在同一时间过期或者Redis实例宕机。解决过期时间加随机值或者做Redis高可用集群。6. 复盘与准备建议这类AI平台公司的笔试题该怎么备6.1 从题目反推候选人的能力模型把整套卷子复盘完你会发现第四范式的笔试背后有一套非常清晰的能力模型它不招只会刷题的人而招基础扎实、能落地、懂系统的后端工程师。第一层是语言和数据结构的基本功。C/C的指针、内存布局Java的集合与并发这些是底层能力决定了你能不能写出可靠的生产代码。第二层是操作系统的理解。Linux命令、进程调度、IO模型、内存管理这些决定了你在线上出问题时能不能快速定位。第三层是数据存储与场景设计。MySQL索引、Redis缓存策略这些决定了你能不能设计出支撑高并发业务的系统。AI平台公司的特殊性在于它的业务链路比普通互联网应用更复杂。一个在线推理服务前端是特征网关中间是模型推理引擎后端是特征存储和模型版本管理任何一个环节出问题都会影响业务。所以笔试题里才会出现那些CPU飙升排查缓存策略设计的场景题——它们不是在为难你而是在提前筛选那些有系统思维的人。6.2 我踩过的坑和后来总结的备考节奏最后说说备考的节奏和我踩过的坑这些经验比具体的题目更有复现价值。第一个坑是过度刷偏题怪题。秋招初期我花了不少时间在红黑树手写、跳表实现这类高难度算法上但第四范式的编程题难度适中更看重基础算法的熟练度和边界处理。后来我调整策略把精力集中在数组、链表、二叉树、字符串、动态规划这五类高频题型上每类刷熟20题左右效果比盲目追求难题好得多。第二个坑是忽略Linux和数据库的实操。笔试前的两三周我把时间几乎全花在了算法和Java基础上Linux只是背了背命令语法结果在简答题上吃了亏。你以为会了ps aux查看进程、top查看CPU、free查看内存就够了但人家问的是如何用这些命令判断系统瓶颈这需要真实环境下的经验积累。建议抽时间在一台Linux服务器上实际部署一个Web应用制造CPU满载、内存不足、IO阻塞这些问题再用命令去排查一遍这个经历对答场景题的帮助是纯背书比不了的。第三个坑是编程题只写代码不写注释。笔试平台的阅卷不一定逐行读代码但你在关键步骤加上注释、写明复杂度和思路能明显提升阅卷体验。我当时TopK那道题的注释写得清楚后面面试时面试官还专门夸了一句。如果再给备考一次机会我会按四个阶段来安排基础夯实期2周过一遍C语言指针、Java集合源码、操作系统核心概念、MySQL索引原理建立知识框架。刷题集中期3周每天2-3道算法题以高频题型为主每道题都写思路注释和复杂度分析。场景实战期1周在真实Linux环境做排查实验把top、strace、netstat、jstat这些工具用熟同时刷SQL优化场景题。冲刺调整期3天做几套完整模拟题控制答题时间整理错题本重点看概念辨析类题目。这套节奏不一定适合所有人但方向是对的基础题求稳、算法题求熟、场景题求真实感。第四范式2020秋招的这套笔试题本质上是一面镜子照出的是你对后端工程基础的理解深度。把这张卷子研究透了再去准备其他AI公司或者中大型互联网公司的后端笔试你都会发现它们考察的内核是相通的。我在实际准备过程中最大的体会是笔试最后拼的不是你会做多少难题而是简单题能不能又快又准地拿满分。那些数组指针、Linux机制、并发原理恰恰是决定排名的关键。少背一点花哨的技巧多花时间把基础概念吃透这是我对所有准备后端岗笔试的朋友最实在的建议。