FEATURED · 精选文章

复盘人人网2015研发笔试卷:算法、操作系统与数据库考点

发布时间 / 2026/8/30 21:20:40
来源 / 创域科博编辑部
栏目 / 资讯中心
复盘人人网2015研发笔试卷:算法、操作系统与数据库考点 前几天整理旧资料翻出一份PDF文件名写着《人人网2015研发笔试卷E》。说实话看到这个名字的时候愣了几秒——那会儿人人网还是很多应届生眼里的热门去处从校内网改名之后社交产品做得风生水起研发笔试也出了好几套题E卷就是其中之一。十年过去产品起起落落但这张卷子里的知识点拿出来今天再看一遍依然有价值。很多读者可能会问一份2015年的笔试卷放到现在还有什么用我的看法是笔试这关考的东西和互联网业务的风口是两回事。无论产品怎么变研发岗笔试的筛选逻辑几乎没变过——用一套标准化题目快速过滤候选人考察数据结构、算法、操作系统、计算机网络、数据库、语言基础再配几道逻辑题。这套框架到今天仍然是主流。所以这个复盘不是贩卖情怀而是帮你看清这类笔试的出题节奏顺便验证一下自己的基础功到底扎不扎实。1. 十年后重看这张卷子为什么还有复盘价值1.1 当年人人网研发笔试的基本盘先说清楚大背景。2015年移动互联网还在高速增长期人人网虽然不再是当年校园社交的绝对霸主但体量依然不小校招笔试的题目质量也一直在线。研发岗的笔试基本是线下统一考试一张卷子两个小时题型以问答和编程题为主。E卷是同一套笔试题的平行版本之一和A到D卷的结构类似难度也不会差太多主要目的是防止相邻考生互相抄。我当时按同批次题目和出题风格做了一份分布梳理大致是这样考察模块常见的题目形态大致占比数据结构与算法手写代码、递归、链表、字符串处理30%以上操作系统死锁、进程线程、内存管理、页面置换15%到20%计算机网络TCP握手、UDP、HTTP、拥塞控制15%左右编程语言基础C内存布局、指针、构造析构15%左右数据库SQL编写、索引、事务10%到15%逻辑与智力题推理题、最优策略10%左右这个分布不是我瞎编的你去看2015年前后各家互联网公司的研发笔试题基本上都是这个配方。算法和数据结构一定是大头操作系统和网络必有一席之地语言基础用来卡细节数据库考察实际写SQL的能力最后用逻辑题看看你遇到陌生问题时能不能拆解。1.2 笔试过关的本质是把基础知识连成闭环做过笔试题的人都有这种感受很多题单独拿出来都见过但放到一张卷子里两个小时做完就手忙脚乱。根本原因在于基础知识是零散的没有形成闭环。所谓闭环就是每看到一个考点你能立刻反应出它和哪些知识点有关系。比如卷子里考到TCP三次握手如果你只记了“三次握手”四个字那道题大概率只能拿一两分如果你能把握手的过程、为什么是三次不是两次、SYN洪泛攻击、初始序列号的作用、与四次挥手的关系全部串起来那道题闭着眼睛也能拿全分。这正是当年人人网笔试卷E这类老题目的价值所在。它考的从来不是“偏、难、怪”而是看你把大学四年最重要的几门课吃透了多少。这个逻辑放在今天的笔试上依然成立。2. 算法题复盘字符串、链表和Top K的考察逻辑算法题是整张卷子的核心按我的回忆和同类试卷对比E卷里算法题至少占了三道以上。下面这几类题都是那个年代研发笔试的高频代表现在互联网公司笔试也还经常出现。2.1 字符串压缩边界条件比主逻辑更值钱这类题在当年的卷子里很典型原题大致是给定一个字符串把连续出现的字符按“字符出现次数”的方式压缩比如aabcccccaaa变为a2b1c5a3。如果压缩后的字符串长度不小于原字符串则返回原字符串。看起来很简单的字符串处理题但能在一张限时卷子里拿满分的同学并不多。我把一个可用的解法写出来#include string using namespace std; string compressString(const string s) { if (s.empty()) return s; string result; int count 1; for (int i 1; i s.size(); i) { if (s[i] s[i - 1]) { count; } else { result.push_back(s[i - 1]); result to_string(count); count 1; } } result.push_back(s.back()); result to_string(count); return result.size() s.size() ? result : s; }这题的考察点不止一个。第一循环终止条件怎么设计能不能处理字符串末尾的字符段第二压缩后字符串没变短时要返回原字符串这个分支很容易被漏掉第三字符计数超过一位数的时候转字符串是否正确。我当年见过不少人主逻辑写得很顺结果就是在边界条件上翻车。比如字符串是a时压缩结果是a1长度反而变长应该返回原串。又比如空字符串很多人没判断就直接段错误。面试官出这种题想看的不是你能不能写出 for 循环而是你写代码有没有边界意识。2.2 单链表反转两种写法的对比链表反转几乎是必考题。2015年是这样现在依然是这样。这个题有两个主流方向迭代法和递归法两种都要能手写出来。迭代版本的思路是维护三个指针当前节点、前驱节点、下一个节点。每次把当前节点的 next 指向前驱然后整体前进一位。struct ListNode { int val; ListNode* next; ListNode(int x) : val(x), next(nullptr) {} }; ListNode* reverseList(ListNode* head) { ListNode* prev nullptr; ListNode* cur head; while (cur) { ListNode* nextNode cur-next; cur-next prev; prev cur; cur nextNode; } return prev; }递归版本更短但难度更高。递归的思考方式是从后往前反转先递归反转后继节点然后把当前节点的指针接到反转后的链表尾部。很多人在笔试时一紧张就绕进递归旋涡里所以我建议笔试优先用迭代版本它更直观、不容易写错。这道题看似基础实际是在考察两个能力第一你是否理解指针操作的时间顺序第二递归场景下你是否能跟踪调用栈的返回关系。如果打算面大厂建议把迭代和递归都写在纸上练熟每个版本三分钟写完是基本要求。2.3 Top K从排序到快速选择的思路演进卷子里还有一类题我印象很深“找出一个无序数组中第K大的数”。很多人上来就说排序一排序就是O(n log n)虽然不扣分但也拿不到满分。出题人的深层意图是看你知不知道有更优解。常规演进路径是这样先想到排序再想到用一个大小为K的小顶堆维护前K个最大元素时间复杂度O(n log K)最后如果能写出快速选择quick select平均时间复杂度能降到O(n)。快速选择的核心是快排的partition过程。每次把数组分成左右两块比较基准值的位置和K的关系只往一边递归。我写一份返回第K大元素的版本#include vector using namespace std; int partition(vectorint arr, int left, int right) { int pivot arr[right]; int i left; for (int j left; j right; j) { if (arr[j] pivot) { swap(arr[i], arr[j]); i; } } swap(arr[i], arr[right]); return i; } int quickSelect(vectorint arr, int left, int right, int k) { if (left right) return arr[left]; int p partition(arr, left, right); int count p - left 1; if (count k) return arr[p]; if (count k) return quickSelect(arr, left, p - 1, k); return quickSelect(arr, p 1, right, k - count); }注意我在 partition 里选了最右元素做基准值。笔试时这样写最不容易出错但你的脑子里要清楚当输入接近有序时这种写法会退化到O(n²)。所以笔试答题时建议在题解里补一句“实际工程中会选择随机基准值以避免退化”面试官看到这句话会认为你是真的理解而不是只会背代码。3. 操作系统与网络死锁、握手和内存管理的出题套路操作系统和网络是笔试的固定板块也是很多人容易忽视的部分。算法题不会就是不会但操作系统和网络这两门的细节极多复习起来没有边界于是很多人干脆战略性放弃。事实上这部分恰恰是最容易靠短时间背诵拿分的。3.1 死锁四条件送分题还是拉分题“死锁产生的四个必要条件是什么”大概是2015年笔试里出现频率最高的操作系统问题E卷几乎不可能放过这个考点。标准答案只有一句话互斥、持有并等待、不可剥夺、循环等待。但这道题真正的区分度在第二问“如何破坏这四个条件”很多同学只背了条件不会应用。比如破坏“持有并等待”可以通过一次性申请所有资源破坏“不可剥夺”可以在资源无法获得时主动释放已占有的资源破坏“循环等待”可以对资源编号按序申请。如果能再举一个具体的死锁例子比如两个线程互相等待对方释放锁这道题基本就拿稳了。笔试答题有个技巧简答题别只写关键词要把“概念条件破坏方法例子”四个层次写全。阅卷人不是只看你有没有写到点子上还在看你的表达是否完整。3.2 TCP三次握手为什么必须是三次网络题绕不开TCP。2015年的E卷我印象中问了“为什么TCP建立连接需要三次握手两次行不行”这题到今天仍然是面试高频题答得好不好直接暴露你到底是背了八股还是真的理解了协议设计。三次握手要解决的核心问题有两个一是让双方确认对方的收发能力正常二是同步初始序列号。如果只有两次握手服务端发出SYNACK之后就直接进入ESTABLISHED状态但客户端可能因为网络延迟没有收到这个报文它就会认为自己没连接上不发送数据。服务端却一直等着白白维护连接资源。更严重的问题是如果客户端发出的SYN因为网络原因滞留在连接关闭后才到达服务端服务端会误以为这是一次新连接请求于是回复SYNACK并建立起一条已经过期的连接。有了第三次握手客户端发现这条连接不是自己发起的就不会再回应服务端等不到第三次ACK就会释放连接。所以答这道题的时候别只背“三次握手是为了确认双方收发能力”这一句话最好能画出状态变迁把拥塞窗口、SYN洪泛这些扩展知识也带上一两句。这张卷子考的是理解深度不是背诵广度。3.3 虚拟内存与页面置换操作系统还有一类题特别经典就是给你一个页面访问序列问在指定物理块数量下FIFO和LRU两种置换算法各产生多少次缺页。这类题算起来很繁琐但实际上是送分题只要你按表格一步步填稳拿。我常用来练手的一个经典序列是7 0 1 2 0 3 0 4 2 3 0 3 2 1 2 0 1 7 0 1物理块数设为3。我直接说结论FIFO缺页15次LRU缺页12次。这个例子特别适合用来理解两者的差异。FIFO看的是调入内存的时间谁先来谁先走。比如访问序列第4个元素2时7是最早进来的所以2替换7。LRU看的是最近一次被访问的时间谁最长时间没被用到谁先走。在访问第6个元素3时内存里是2、0、1其中1最久没被访问所以3替换1而不是替换2。这里要用一个常见的类比来理解FIFO像食堂排队先来的先打饭走人LRU像宿舍衣柜最近穿过的衣服放最外面好久没穿的压箱底要扔的时候优先扔它。区别在于访问序列中某个页面可能在很早就被再次使用这时LRU的优势就体现出来了。笔试中这种题一定要把过程表格画出来不要心算。用表格列清楚访问次数、访问页面、内存状态、是否缺页阅卷人看得清楚你自己也不容易出错。4. 语言与数据库C陷阱、索引和事务的笔试常见问法4.1 内存对齐一道考住很多人的小题语言基础题里面C内存对齐是那个年代笔试的常客现在偶尔也出现在面试题里。E卷里这类题我按当时的风格还原一道struct A { char a; int b; char c; }; struct B { char a; char c; int b; };问这两个结构体分别占多少字节。很多人凭直觉觉得都是6字节错。在默认4字节对齐的编译环境下结构体A占12字节结构体B占8字节。原因是编译器在存储成员时会自动填充空白字节每个成员的偏移量必须是其自身对齐数的整数倍。结构体A里a占1字节后b是int类型占4字节所以需要填充3个字节让b对齐到偏移4的位置c是1字节放在偏移8处最后整个结构体大小必须是最大对齐数4的整数倍所以从9补齐到12。结构体B把两个char放在前面a占偏移0c占偏移1b放到偏移4总大小刚好8字节。笔试遇到这道题我的建议是快速找两个关键数最大对齐数和成员偏移规则。按“偏移按成员对齐数整数倍放置总大小按最大对齐数整数倍补齐”的规则算30秒就能出来。此外你还可以顺带说一句“#pragma pack可以修改对齐方式”这句话能让阅卷人感觉你不只是会背规则而是真做过底层开发。4.2 指针和引用的差异以及C对象的常见坑C的题还经常考指针和引用的区别。标准答案大概有这几条引用在定义时必须初始化指针不需要引用不能更改绑定对象指针可以引用不能为空指针可以为空sizeof引用得到的是所引用对象的大小sizeof指针在32位平台是4字节、64位平台是8字节。这道题的区分度在于很多同学能说出前两条却忽略了引用在函数重载和拷贝构造里的一些细节。比如“拷贝构造函数为什么参数必须是引用类型”正确的解释是如果传值调用拷贝构造函数就需要按值传参而按值传参又需要调用拷贝构造函数这会形成无限递归。这个点如果能在笔试卷子里写出来分数会明显高一档。语言题在整张卷子里占比不算最大但它是最容易暴露出基础不扎实的地方。一道8分的C陷阱题懂的人拿满分半懂的人拿2分差距非常大。4.3 SQL多表查询从“会写”到“写得对”数据库题基本必考SQL编写。当年的试卷场景很常见学生表、课程表、选课表三张表要求查询“选了数据库课程但没选网络课程的学生姓名”。一个能用的SQL是这样SELECT s.name FROM Student s WHERE s.id IN ( SELECT sc.sid FROM SC sc JOIN Course c ON sc.cid c.cid WHERE c.name 数据库 ) AND s.id NOT IN ( SELECT sc.sid FROM SC sc JOIN Course c ON sc.cid c.cid WHERE c.name 网络 );这个题考察的不只是会写JOIN而是你能不能把业务逻辑转换成集合思维。IN表示“在集合内”NOT IN表示“不在集合内”整个查询本质是集合的交与差。更进阶的写法是使用EXISTS原理是关联子查询逐行判断学生是否存在对应的选课记录。两种写法面试官都会认可但如果你能在卷子里把两种都写出来再说明IN适合子查询结果集小的情况、EXISTS在子查询表大时性能更好数据库这关就基本无忧了。4.4 索引结构为什么是B树而不是红黑树数据库常考的另一道题是“为什么InnoDB的索引结构用B树”。一道题能答出三层深度分数就完全不一样。第一层是B树矮胖树高大概只有3到4层磁盘IO次数少查询效率稳定第二层是非叶子节点不存数据只存索引键和指针一个节点能装更多条目所以树更矮第三层是叶子节点通过链表相连支持范围查询和排序这在SQL的WHERE和ORDER BY场景里非常重要。对比红黑树它虽然也是平衡树但高度在log₂n级别一个几百万行数据的表红黑树高度可能有20多层每次向下查找都是一次磁盘IO代价太高。所以红黑树适合在内存中做关联容器比如C的map、set而数据库索引这种需要大量磁盘交互的场景B树是更合适的选择。笔试试卷里能写到这个层面已经不只是一道八股题了而是在向面试官证明你真的理解存储引擎。4.5 事务特性和隔离级别一张表解决的事数据库最后常考的是事务。ACID四个特性——原子性、一致性、隔离性、持久性基本是送分题。但后面的问题就有点深度了事务隔离级别有哪几种分别解决什么问题。用一张表可以讲清楚隔离级别脏读不可重复读幻读读未提交可能可能可能读已提交不会可能可能可重复读不会不会可能InnoDB默认级别下通过间隙锁解决串行化不会不会不会笔试里最好再举个具体例子。所谓脏读就是事务A修改了数据还没提交事务B就读到了这条修改如果事务A回滚事务B读到的就是脏数据。不可重复读是同一事务内两次读取同一行结果不一致因为其他事务在这期间提交了修改。幻读是同一个查询条件两次查询返回的行数不同因为其他事务插入了新行。MySQL默认隔离级别是可重复读而且InnoDB引擎在可重复读级别下通过间隙锁协议解决了大多数幻读情况。这个知识已经接近业务开发的实际场景了写出来会让整份答卷的质量上一个台阶。5. 那道传了十年的智力题和它背后的思维能力笔试卷最后通常会来一道逻辑题人人网E卷里我印象很深的是“25匹马5个赛道最少比赛几次能找出最快的3匹”。这道题现在很多面试官还在用值得认真讲一遍。先说答案7次。这个结论让很多人意外你以为至少10次但通过分治只需要7次。推理过程如下。第一步把25匹马分成5组每组5匹各跑一轮。共5次得到每组内部的排名。第二步让每组第一名跑一轮。这是第6次。假设这次比赛的结果按快慢排序五组分别是A、B、C、D、E那么A组第一名就是全场总冠军因为它跑赢了其他所有组的第一名。第三步剩下的候选马没有你想象中那么多。D组和E组的所有马都可以排除因为它们组第一名都没进总前五组内其他马更不可能进总前三。C组只能留下第一名因为C组第一已经排在A组第一和B组第一后面C组第二即使再快也不可能挤进前三。B组可以留下第一名和第二名。A组可以留下第二名和第三名因为A组第一已经占了前三的一个名额。所以最终需要跑第7次的三匹候选马是A组第二、A组第三、B组第一、B组第二、C组第一。五匹马跑一轮取前两名再加上A组第一就是全场最快的三匹马。这道题的精髓不在于你智商高不高而在于你有没有结构化思维。很多人一上来就想着把所有马都跑一遍却没有意识到“排名信息”可以帮你排除大量无效候选。这道题放到研发笔试里的意图也在于此不是考察你有没有见过这道题而是看你在信息不完整的条件下能不能通过推理缩小问题规模。后来我在面试人时也喜欢问这个题见过三种典型反应。一种是背过答案的上来就说7次但问为什么选那几匹就支支吾吾一种是现场推出来但过程混乱说明逻辑链条清晰度不够还有一种能一边推导一边画出候选树这种人即使在真实业务里遇到性能优化问题也大概率知道如何缩小排查范围。6. 备考启示从这份卷子里能带走的笔试准备策略6.1 把高频考点串成知识闭环复盘完这份卷子我想说点更实际的。很多准备笔试的人容易陷入盲目刷题今天做几道链表明天看两眼数据库后天又去背网络结果每个方向都是半桶水。2015年卷子给我的启示是笔试考的不是单点而是面。我建议按模块做知识闭环。算法以数组、链表、字符串、二叉树和动态规划为主每天一个类型刷完一轮后再做混合题操作系统把进程与线程、死锁、虚拟内存、页面置换做成一套笔记边整理边做计算题网络从TCP和UDP出发把三次握手、四次挥手、流量控制和拥塞控制串起来画成状态图数据库围绕索引、事务、SQL三块反复练。有一个很有效的方法每复习一个模块就试着出一道和原题类似的题目然后自己回答。比如复习完页面置换就自己编一个访问序列用FIFO和LRU各算一遍缺页次数。能自己出题、自己能讲到别人听懂这个知识点就真正内化了。6.2 笔试现场的节奏、取舍和边界检查笔试现场最重要的是时间分配。一张两个小时的卷子算法题往往要占掉一半时间如果你在某道题上卡了十五分钟没有任何思路先标记跳过去把后面会的题做完再回头。宁可每一题都拿一部分分也不要一道题磨到底。做编程题时我习惯先写注释把整体思路列出来。比如链表反转这道题先在纸上写“迭代prev,cur,next三指针”然后再开始写代码。这样即使最后代码没有跑通阅卷人也看得到你的思路路径能给思路分。还有一条是老生常谈但极其重要的边界检查。空数组、单个元素、字符串末尾、链表只有一个节点、K值等于1或等于数组长度这些都是笔试题最爱埋的雷。写完代码之后花一分钟用一个简单输入在脑子里走一遍很多低级错误当场就能发现。6.3 十年过去了笔试变在哪儿没变在哪儿现在回头对比笔试考察的底层能力其实没变。算法和数据结构仍然是第一关操作系统和网络依然是基础中的基础SQL写的熟不熟练依旧一眼见高下。这些知识就像程序员的地基不管你后来做业务、做中间件、还是做算法工程都需要靠它们兜底。变化也很大。第一技术栈更宽了2015年那会儿很多公司默认应聘者用C或Java现在Go、Rust、Python、TypeScript都成了常见选项第二OJ在线评测成为主流代码跑不过用例就直接判错不像纸质卷子还能看思路给分第三算法题的难度整体上抬高了hard题在现在的校招笔试里不算稀罕这在当年是比较少见的第四面试环节对项目经历的权重增加了笔试只是入场券能不能拿到offer更多看技术面和HR面的综合表现。所以我的建议是不要迷信“刷完几百道题就能包过”这种话但也不要轻视笔试因为笔试就是那道最基础的门槛。把这份老卷子复盘清楚本质上是在帮你确认自己对这些“不变的地基”掌握得怎么样。地基稳了上面盖什么楼都行。
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻