前阵子整理旧硬盘,翻出一份2016年美丽联合(蘑菇街和美丽说合并后的公司)研发工程师的笔试题归档。当时也算电商行业比较有代表性的后端岗位试卷,现在回头看,虽然技术栈有些年头了,但考察的底层逻辑、算法思路和工程素养,放到今天依然有参考价值。这篇文章我就以这套题为线索,把研发工程师笔试里反复出现的高频考点、实战解法、以及我自己刷题踩过的坑一次性讲透,给正在准备大厂或中型互联网公司校招、跳槽的朋友一份能直接上手的复习地图。
1. 2016年笔试题的整体设计与考点分布
1.1 试卷结构和考察思路
先聊试卷本身。美丽联合2016年研发工程师笔试题,整体分两大块:客观题和主观编程题。客观题覆盖计算机基础,包括数据结构、操作系统、网络、数据库、Java或C++语言特性;主观题一般是1-2道算法编程题,偶尔附带一道系统设计或场景题。时间一般是90到120分钟,题量在30到50道之间,难度呈阶梯状,前面送分,中间拉差距,最后压轴。
这套结构现在看依然经典。基础知识用来筛掉基础不牢的候选者,编程题用来筛掉只会背概念不会写代码的人,系统设计题则用来判断候选人有没有真正的工程思维。对于面试官来说,笔试不是要你考满分,而是要在有限时间内暴露你的真实水平。所以我的建议是,复习时不要平均用力,基础题保证正确率,算法题至少AC一题,设计题言之有物,总分就不会难看。
1.2 高频考点与分值占比
从历年各大厂笔试题反推,2016年前后后端岗位笔试的高频考点集中在以下几个方面:
- 数据结构与算法(占比约30%-40%):数组、链表、栈、队列、二叉树、图、排序、查找、动态规划、贪心、字符串处理。
- 计算机基础(占比约30%):操作系统进程线程、内存管理、网络TCP/IP、HTTP协议、数据库索引与事务。
- 语言特性(占比约20%):Java集合源码、异常机制、JVM内存模型、并发编程,或C++的指针、内存管理、STL。
- 智力题与场景设计(占比约10%-20%):逻辑推理、概率题、系统架构设计、缓存与消息队列使用。
对照这份权重,你会发现一个规律:数据结构与算法永远是笔试的重头戏,因为这类题最容易标准化评分,也最能区分“背题党”和“真会写代码的人”。同时数据库和网络几乎是必考,因为后端开发日常就在跟这两块打交道。
2. 核心题型深度解析与解题思路
2.1 编程题常考的算法模型与模板
美丽联合这类电商公司,笔试题编程题很少出纯竞赛题,更多是带有业务背景的算法题。比如订单排序、商品去重、用户访问日志分析、最大促销折扣组合等。剥掉业务外壳后,核心还是那几类经典算法。
我整理了几类出现频率极高的算法模型,以及对应的解题模板:
第一类:数组与双指针。题目特征是有序数组、原地操作、寻找子数组或满足条件的元素对。典型题是“有序数组两数之和”、“移动零”、“最长无重复子串”。解法核心是维护左右两个指针,根据条件移动边界,把时间复杂度从O(n^2)降到O(n)。这类题是笔试送分题,必须拿满。
def two_sum_sorted(nums, target): left, right = 0, len(nums) - 1 while left < right: current = nums[left] + nums[right] if current == target: return [left, right] elif current < target: left += 1 else: right -= 1 return []第二类:二叉树遍历与递归。题目特征是按某种顺序输出节点、求树的深度、判断对称树、最近公共祖先。解法核心是明确递归终止条件和单层处理逻辑。我当时总结的经验是:二叉树题先把“前中后序、层序”这四种遍历背到肌肉记忆,再练递归,正确率能提升一半。
第三类:动态规划。题目特征是最值问题,比如最大子序和、最短路径、编辑距离、背包问题。这类题是拉开差距的关键。破解思路分四步:定义dp数组含义、找状态转移方程、确定初始化、确定遍历顺序。状态转移方程写不出来时,先暴力递归加备忘录,再改迭代,这个思路在笔试时间紧张时特别有用。
第四类:字符串处理。题目特征是高精度加法、最长公共前缀、字符串翻转、正则匹配。多数题不考复杂算法,而是考边界处理和代码基本功。
提示:笔试编程题和LeetCode有个关键区别——笔试环境通常没有测试用例提示,要求你自己处理输入输出。所以复习时一定要动手在本地或在线IDE里写完整代码,包括处理输入格式和边界条件,不能只刷LeetCode的函数体。
2.2 数据结构与语言特性的经典概念题
这份笔试的客观题部分,高频出现的概念题我梳理了几个典型:
关于HashMap:必问底层结构、put和get流程、扩容机制、为什么线程不安全、ConcurrentHashMap怎么保证线程安全。2016年JDK 8已经普及,所以红黑树优化也是考点。面试官喜欢连环追问,笔试则会直接考“HashMap扩容时链表如何拆分”、“为什么加载因子是0.75”这类细节。
关于线程池:必考核心参数(corePoolSize、maximumPoolSize、keepAliveTime、workQueue、handler),以及执行流程。记忆口诀是“先核心、再队列、再非核心、最后拒绝策略”。笔试常以选择题形式给出参数组合,问线程池最终怎么处理新任务。
关于JVM内存模型:必考堆、栈、方法区、程序计数器的分工,以及垃圾回收算法。笔试常考“哪些对象可以进入老年代”、“Minor GC和Full GC的触发条件”、“类加载的双亲委派模型”。这块没有捷径,只能把周志明《深入理解Java虚拟机》前三章吃透。
关于TCP和HTTP:必考三次握手四次挥手、TIME_WAIT状态、TCP和UDP区别、GET和POST区别、HTTP状态码语义。电商场景还会延伸问Cookie和Session、HTTPS握手过程。复习时用抓包工具亲手看一次握手过程,印象深得多。
2.3 数据库与电商场景的系统设计题
数据库在研发工程师笔试里基本是必考,而且和业务场景结合紧密。美丽联合是电商公司,所以考数据库时尤其爱考订单系统、商品系统、促销系统相关的表设计和查询优化。
高频考点集中在:索引失效场景(最左前缀、like以%开头、or连接、函数计算)、事务隔离级别(读未提交、读已提交、可重复读、串行化)及各自解决的问题、MVCC原理、B+树和哈希索引的区别、分库分表策略、SQL慢查询排查。
系统设计题则更考验综合能力。常见题目包括:设计一个短链接系统、设计一个购物车、设计一个秒杀系统、设计一个用户关注关系表。这类题没有标准答案,但评审有明确偏好。我的答题框架是四层:存储层(用什么数据库、表结构怎么设计)、缓存层(哪些数据放Redis、缓存一致性怎么保证)、异步层(哪些操作可以走消息队列削峰)、容错层(挂了怎么办、限流降级怎么做)。只要四层讲清楚,哪怕方案有缺陷,分数也不会低。
比如面试官如果问“设计一个秒杀系统”,我建议的回答思路是:
- 前端:按钮置灰限流、CDN扛静态流量。
- 网关层:接口限流,令牌桶算法。
- 应用层:Redis预减库存,防止请求直接打到数据库。
- 消息队列:订单创建异步化,削峰填谷。
- 数据库:库存扣减用乐观锁或原子更新,防止超卖。
- 兜底:库存不足直接返回失败,秒杀结束后对账。
这个思路放到今天的系统设计面试里依然完全适用。
3. 从真题到实战:刷题路线与时间分配
3.1 按优先级排序的复习路线
我见过太多人复习笔试时东一榔头西一棒子,今天刷链表,明天看网络,后天又去背JVM,结果一个月下来什么都没吃透。正确做法是按优先级规划路线,把时间花在性价比最高的地方。
我推荐的复习顺序是:
第一阶段(约40%时间):算法与数据结构。优先级从高到低:数组、链表、栈、队列、哈希表、二叉树、排序、二分查找、动态规划、DFS/BFS、贪心、堆。这个顺序不是随意的,数组和链表是最基础的线性结构,二叉树是递归思维的训练场,动态规划和搜索是拔高题,必须放在基础牢固后再攻。算法题每天保持2到4道的量,重点是反复刷而不是追求数量。
第二阶段(约25%时间):数据库与计算机网络。数据库优先复习索引、事务、锁和SQL优化,网络优先复习TCP/UDP、HTTP/HTTPS、DNS流程。这两块是客观题的大头,也是面试追问的重灾区,理论基础必须扎实。
第三阶段(约20%时间):语言特性和JVM。如果你是Java岗,把集合源码、并发工具、JVM内存和GC过一遍;如果是C++岗,重点看指针、虚函数、内存管理、STL底层。这块不需要面面俱到,抓住高频考点即可。
第四阶段(约15%时间):系统设计和智力题。设计题看3到5个经典案例,把架构图和数据流在纸上画熟;智力题刷常见的概率题、逻辑题,比如“1000瓶药水找毒药”、“两个鸡蛋问题”、“赛马找前三”,掌握通用解法即可,没必要花大量时间。
3.2 高效刷题的三遍法
很多候选人刷题只刷一遍,AC了就扔,过两周再看,代码完全写不出来。这是因为编码能力本质上是“内化”的过程,不是“看过”的过程。我自己实践下来最好用的是三遍法。
第一遍:拿到题目先不看题解,自己想思路,实在想不出来再参考最优解。这道题就算“见过”了,把解题思路和核心代码用自己的话写在笔记里。
第二遍:隔1到2天,不看笔记,重新在IDE里从零手写这道题。写不出来就返回去看,今天标记为“重做”。这一遍的目标是达到“独立AC”。
第三遍:隔一周,直接用纸笔写代码,模拟笔试环境,不借助IDE提示。然后对着笔记核对,重点检查边界条件和复杂度的最优性。
这个方法看似慢,实际是捷径。因为笔试题库里大量是重复题型,刷透100道经典题,胜过囫囵吞枣500道。
3.3 笔试现场的答题顺序和时间管理
笔试现场最怕的是“死磕”。拿到卷子后,我的固定策略是前5分钟快速浏览所有题目,标记难度等级,然后按“先易后难、先分高后分低”的顺序答题。
具体安排:客观题部分,会做的先做掉,拿不准的标记跳过后再回来,不要在一道概念题上纠缠太久。编程题部分,先写自己最有把握AC的那道,保证至少一道全过,再考虑第二道能不能拿到部分分。很多在线评测系统是按测试用例给分的,所以哪怕代码只能过前面的用例,也要提交,能拿几分是几分。最后留出10到15分钟,检查输入输出格式、变量命名是否拼错、是否有数组越界。
注意:笔试环境通常只允许切换有限次页面,一旦切走不能回退,所以编程题的代码务必先在草稿纸上理清思路,再一次性敲入。另外,在线编辑器一般没有自动保存,记得定期手动点击保存。
4. 常见问题与踩坑经验实录
4.1 编程题常见的失分点
刷题量到了,笔试还有一个隐藏的失分重灾区:代码边界。我复盘美丽联合这套题以及后来我自己出的笔试题时,发现典型错误集中在以下几类:
第一,数组越界和空指针。遍历数组时没考虑长度为0,调用strlen或length()时没判空,字符串处理时没处理末尾字符。解决方法是写代码前先在心里列出空值、单元素、满容量三类测试用例。
第二,整型溢出。笔试里很多求和、乘法题,默认是int范围,但如果题目没明说,就要考虑用long。2016年很多候选人就挂在“链表两数相加”这类看似简单但数据范围很大的题上。
第三,递归没写终止条件或死循环。常见于二叉树题和DFS题。解决办法是“进入递归第一步先写跳出条件”,这个习惯必须刻进本能。
第四,复杂度过高被卡。比如该用HashMap的地方用了List.contains,导致O(n^2)超时。笔试时间紧张时,别急着优化,先想清楚有没有更优数据结构可用。
4.2 知识型题目的混淆点
知识型题目比算法题更阴险的地方在于,很多概念长得很像,容易记混。我挑几个高频混淆点分享:
线程和进程的区别。很多人只背了“进程是资源分配最小单位,线程是CPU调度最小单位”,但一考到“同一个进程内线程共享哪些资源”就露馅。记住:线程共享进程的堆和方法区,但每个线程有独立的程序计数器、虚拟机栈和本地方法栈。
TCP和UDP使用场景。考点不只是“TCP面向连接、UDP无连接”,还会考“哪些应用用哪种协议”。比如视频直播、游戏实时对战、DNS查询用的是UDP,文件传输、邮件、网页浏览用TCP。这个要结合实际场景记忆,而不是死背。
数据库索引失效场景。最经典的是“在索引列上使用函数”和“隐式类型转换”。比如where phone = 13812345678,如果phone是varchar,但传的是数字,索引可能失效。复习时把这几个场景整理成表,比反复看书效率高得多。
4.3 时间不够用的应对策略
笔试题量大,时间不够用是常态。如果你在考场上已经落后于计划,我建议的优先级调整策略是:果断放弃难题,保基础题。比如客观题的最后一道黑科技题,如果读完两遍还没有头绪,直接蒙一个答案,把时间留给编程题。因为编程题一道满分或部分分,价值远高于一道选择题。
另外善用“倒推法”和“排除法”。算法题想不出最优解时,先写暴力解,很多在线判题系统会按通过用例数给分,暴力解也能拿20%到40%的分。系统设计题答不全时,抓住“存储+缓存+异步”三件套展开,至少能拿一个基础分。
5. 从笔试到面试:这套题带来的长期价值
笔试不只是求职的一道门槛,更是一次系统性的知识体检。我通过复盘美丽联合这套2016年的笔试题,最大的收获是发现自己至少有三个地方是“知其然而不知其所以然”的。比如HashMap的扩容机制我知道会发生,但不清楚扩容后链表如何拆分;TCP的TIME_WAIT我知道存在,但说不清为什么要等2MSL。这些薄弱点如果不通过刷题暴露出来,等到线上出故障时再来补,代价就太大了。
所以我的建议是,不管你现在处在求职的哪个阶段,都值得拿这套或同类笔试题做一次模拟测试。以90分钟为限,屏蔽所有干扰,完整做一遍,然后逐题对答案、整理错题、分析错误原因。这个过程比盲目刷300道LeetCode更能定位你的短板。
复习过程中,我还发现一个值得分享的小技巧:准备一个“高频考点速查表”,把每个考点的关键词、易混淆点、口诀写在卡片上,利用通勤、排队等碎片时间反复过。笔试前半小时只看这个表,不看长篇笔记,记忆唤醒效率极高。
如果你能把这套题里面的知识点全部吃透,再延伸复习一遍并发编程和分布式基础,那应付大多数互联网公司的研发工程师笔试基本没有问题了。这套2016年的试卷在今天看来依然是一座很值得挖的富矿,希望这篇文章能帮你把里面的价值都挖出来。
最后再分享一个小经验:笔试答题时如果遇到完全不会的题,千万不要留白。主观题和设计方案题哪怕不会,也要把自己能想到的相关知识点、技术选型写上去。我后来参与笔试阅卷时发现,很多候选人不是因为水平不够被刷,而是因为空着不写,让面试官完全无法判断他的思路。写点东西,至少还有讨论的空间。