尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

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

美团2016研发笔试题全解析:从算法到数据库的考点拆解

美团2016研发笔试题全解析:从算法到数据库的考点拆解 1. 美团2016研发笔试的出题逻辑与岗位画像聊到这套题之前先说个背景。2016年前后的美团正处于从团购向“吃喝玩乐”大平台转型的关键期交易系统、商户系统、调度系统都在快速迭代对研发的需求量很大。那两年的校招笔试题有一个很典型的特点题目不追求偏难怪但覆盖面极广且非常看重“工程落地感”。和纯粹刷LeetCode就能应付的厂子不太一样美团的题里总能闻到一点“业务场景”的味道。这套“2016研发工程师笔试题一”网上流传的版本主要是选择题编程题简答题的组合。我当年做的时候最大的感受是时间不够用。不是题目难到做不出来而是每道题都要想很久尤其是那些“看起来会一选就错”的选项。如果你是准备面大厂研发岗的在校生或者工作两年想跳槽、想系统补基础的同学这套题绝对值得拿来当一面镜子照一照它能照出你知识体系里的窟窿在哪儿。另外要说清楚一个事情本文不是把原题的答案粘贴一遍而是从“这套题到底在考什么、为什么会这样考、以后再遇到怎么答”三个维度去拆。把考点吃透了换一套题你也能应付这才是复盘的价值。1.1 题型分布一套典型的“三合一”研发卷2016年美团研发岗的笔试题型大致可以分成三个板块板块题量占比考察目标典型内容客观选择题约50%知识广度网络、OS、数据库、语言基础、数据结构编程题约30%代码功底链表、动态规划、字符串处理简答/设计题约20%工程思维场景设计、系统瓶颈分析、SQL编写这和我们平时刷的纯算法题有一个重要差异选择题的密度非常高。它要求你在几十秒内对一个小知识点判断对错。这实际上是在模拟真实工作中“快速定位问题”的场景——你不需要每次都把源码全读一遍但要能根据现象快速排除错误方向。我的建议是做这类选择题的时候别只盯着正确选项一定要把每个错误选项为什么错也想清楚。很多题目就是在易混淆的概念上做文章比如“进程和线程的区别”“TCP三次握手的状态变化”这些都是高频考点也是高频失分点。1.2 一个容易被忽略的信号时间分配笔试一共两个小时左右客观题量大、编程题也不轻松。很多人栽在时间分配上选择题磨磨蹭蹭花了80分钟编程题只剩40分钟最后草草交卷。这里有一个实战经验客观题平均每题不能超过1分半钟。遇到需要计算或长文本分析的题先标记跳过把时间腾给编程题。还有一个细节2016年的笔试系统很多还不支持切出页面查资料所以平时就得把常用API、命令、复杂度结论这些“肌肉记忆”练到位。这个习惯放到现在也一样适用哪怕现在的笔试系统更先进面试官依然会看你“不查资料能不能写干净代码”。2. 算法题是重头戏这四类代码题几乎年年出现那年美团的编程题里我最深的感觉是不考偏题但每题都需要你考虑边界。不像有些厂爱出特别长的模拟题美团更倾向于把一道经典问题藏在一个业务描述里。你如果只会写LeetCode上的标准解法不理解背后的复杂度原理很容易在变体上卡壳。2.1 链表类题目考察的是细心和指针操作基本功编程题里经常出现类似这样的题目给定两个链表找到它们的第一个公共节点。这个题目在剑指Offer上出现过看起来很简单但美团的版本往往加了条件——两个链表中可能存在环。先说基础解法。不考虑环的情况下最简单的思路是用哈希表记录第一个链表的所有节点再遍历第二个链表找第一个出现在哈希表中的节点。时间复杂度O(nm)空间复杂度O(n)。如果要做到空间O(1)经典做法是双指针先分别计算两个链表的长度让长链表的指针先走差值步然后两个指针一起走相遇点就是公共节点。如果链表可能有环情况就多了。一个完整的思路是分别判断两个链表是否有环快慢指针法。如果一个有环一个无环肯定没有公共节点直接返回null。如果两个都无环用上面的双指针法。如果两个都有环先找到各自入环的第一个节点。如果入环节点相同说明公共部分在环外如果入环节点不同需要判断一个环的节点是否在另一个环中能走到说明是同一个环返回其中任一个入环节点即可。这个题给我的一个教训是写链表题不是把主流程写对就行而是要像写生产代码一样考虑各种异常输入。空链表、只有一个节点、两个链表完全重合、环的入口就是头节点等这些边界情况笔试的测试用例往往都覆盖到了。2.2 动态规划美团特别爱考的背包与路径变体如果你看多几年美团笔试回忆贴会发现动态规划在编程题里的出镜率极高。2016年那套题里有一道典型的路径类题目给定一个m x n的网格每个格子里有非负数字从左上走到右下每次只能向右或向下求经过的最大路径和或者最小路径和。这个题的正向解法很简单经典的二维DPint maxPathSum(vectorvectorint grid) { int m grid.size(), n grid[0].size(); vectorvectorint dp(m, vectorint(n, 0)); dp[0][0] grid[0][0]; for (int i 1; i m; i) dp[i][0] dp[i-1][0] grid[i][0]; for (int j 1; j n; j) dp[0][j] dp[0][j-1] grid[0][j]; for (int i 1; i m; i) { for (int j 1; j n; j) { dp[i][j] max(dp[i-1][j], dp[i][j-1]) grid[i][j]; } } return dp[m-1][n-1]; }到这里只是热身美团真正的坑在于变体。比如网格中有障碍物1表示障碍0表示可走求路径数要求打印出最大路径和的具体路径不能在DP过程丢失决策记录把“只能向右向下”改成“可以绕路但每个格子最多走一次”。第三种情况基本就变成搜索问题了复杂度完全不一样。备考的时候我的体会是不要满足于把裸题AC掉要把边界条件和常见变化想清楚。比如路径类DP有一个常见的空间优化——把二维dp压缩成一维for (int i 0; i m; i) { for (int j 0; j n; j) { if (i 0 j 0) continue; else if (i 0) dp[j] grid[i][j]; else if (j 0) dp[j] dp[0] grid[i][j]; else dp[j] max(dp[j], dp[j-1]) grid[i][j]; } }这个技巧在笔试中特别实用能省内存代码也不会复杂太多。关键在于想明白滚动数组里每个状态代表的是“上一行”还是“本行之前”的值。2.3 字符串处理永远不要小看“简单题”字符串类编程题往往第一眼看过去很简单但AC率却不高。那年有一道题是要判断两个字符串是否为“变位词”字符组成相同但顺序不同比如listen和silent。最简单的做法是排序后比较时间复杂度O(n log n)。更优的做法是用定长数组做字符计数def is_anagram(a: str, b: str) - bool: if len(a) ! len(b): return False cnt [0] * 256 for ch in a: cnt[ord(ch)] 1 for ch in b: cnt[ord(ch)] - 1 return all(c 0 for c in cnt)但这个题在美团的笔试里通常会加一个条件要求考虑Unicode字符或者要求在只能遍历一次的情况下判断。后一种情况基本需要用哈希表加一个遍历计数或者用异或的思路虽然异或只能查“是否有相同字符”不能查“频次是否相同”但可以作为一个讨论点。这个题给我们的启发是笔试答题时先写最稳妥的解法再优化。很多同学一上来就想写最优解结果边界没处理好反而丢了分。先把排序或计数的解法写对如果还有时间再优化。2.4 排序与二分复杂度分析比实现更重要美团笔试的编程题里不太会只考“写一个快排”而是会考“在两个有序数组中找到第K大的数”这类需要二分思想的问题。这个问题有经典解法在较短的数组上做二分确定分割位置时间复杂度O(log(min(m, n)))。思路可以这样理解假设要在两个有序数组A和B中找第K小元素或者找整体中位数我们可以比较A[K/2-1]和B[K/2-1]每次排除掉较小那一方的前K/2个元素然后K减半继续递归。当年我备考时花了很多时间把这类题全部自己推一遍而不是直接看答案。比如两个数组长度分别为5和7K6时手动画出分割线和排除过程每一步都验证一下为什么排除是安全的。这个推演过程非常花时间但一旦真弄明白了笔试时根本不用背代码现场就能写出来。3. 计算机网络考点网线拔了还能不能通考的是机制深度美团笔试的计算机网络题目普遍比学校期末考试要深入一截。它不问你“TCP和UDP哪个是面向连接的”而是给出一个场景让你判断协议栈的行为。我特别记得那一年的选择题里有好几道都是关于HTTP协议细节和TCP拥塞控制的没有扎实的底层认知基本只能靠蒙。3.1 HTTP协议状态码和请求头是送分题还是送命题有一道典型的题当浏览器访问一个不存在的资源时服务器应该返回哪个状态码正确答案是404。但美团会把它包装成“一个静态资源服务器当用户请求的资源不存在但请求路径中包含.html后缀时应该返回什么”这个场景下很多服务器会返回403或410原因是安全策略限制而不是资源不存在。这题就考你的HTTP状态码语义是否真正清楚而不是死记硬背。同样要注意的状态码还有301 Moved Permanently与302 Found的区别前者是永久重定向浏览器会缓存后者是临时重定向默认用GET方法重发请求。304 Not Modified配合If-Modified-Since或ETag使用是HTTP缓存机制的核心。502 Bad Gateway与504 Gateway Timeout一个说明网关收到无效响应一个说明网关超时。如果复习时间有限我建议把RFC文档里每个状态码的“触发条件”和“响应头特征”完整过一遍。因为笔试选择题就爱从“触发条件”和“响应头特征”里挖坑。3.2 TCP三次握手与四次挥手必考但常被忽略细节这里有一道高频选择题TCP建立连接时第三次握手时客户端发送的ACK如果丢失会发生什么很多人第一反应是“那连接就没建立成功”。实际上如果服务器在第二次握手中收到了SYN并发送了SYNACK那么对于服务器来说连接已经处于SYN_RCVD状态。当客户端的ACK丢失服务器会重传SYNACK直到超时。此时客户端的TCP状态已经是ESTABLISHED并且可能已经开始发送数据。这个知识点考得很细但确实重要它体现了TCP状态机的鲁棒性。我在实际工作中排查过一个问题——客户端发起了请求但服务器迟迟不处理客户端日志显示连接已建立服务器端连接却一直处于SYN_RCVD。最后发现是防火墙把服务器的SYNACK丢了导致的和这个考点完全对应。TCP相关的高频考点还包括四次挥手中的TIME_WAIT状态主动关闭方需要等待2MSL为什么因为要确保最后一个ACK被接收方收到以及让旧连接的所有报文在网络中消失。拥塞控制的四个阶段慢启动、拥塞避免、快重传、快恢复。美团喜欢考“当发生了超时重传拥塞窗口如何变化”。滑动窗口与零窗口探测这个偏实际但考察TCP流量控制时会用到。3.3 TCP与UDP的选择从业务场景反推选择题偶尔会这样出下面哪种业务适合使用UDP协议请从给出的几个业务场景里挑。适合UDP的场景一般来说有三个特征允许数据丢失但要求低延迟如视频直播、语音通话数据包小且频繁用TCP建立连接的开销太大业务层自己做重传和顺序控制比如游戏同步协议很多就是基于UDP再封一层可靠性机制。我在工作中做过一个高并发日志上报系统最开始用了TCP短连接结果在高峰期连接建立的开销占了太多CPU后来改成UDP加应用层批量确认才把性能压下来。笔试时如果碰到这种场景判断题一定记得从这三个维度去分析而不是单纯记“TCP可靠、UDP不可靠”。4. 操作系统与Linux写算法之外的基本功美团笔试的操作系统题目整体难度中等偏上但绝大多数是常规考点。关键在于要能快速、准确地给出结论而不是“好像在哪里见过”。4.1 进程与线程资源分配与调度的基本盘进程和线程的对比是每次笔试都会见到的。核心考点有进程是资源分配的最小单位线程是CPU调度的最小单位。同一进程内的线程共享地址空间、文件描述符、信号处理器等资源但各自拥有独立的栈和寄存器上下文。进程间的通信方式管道、消息队列、共享内存、信号量、Socket。其中共享内存是速度最快的IPC方式但需要同步机制配合。线程同步常用锁、条件变量、信号量。美团特别喜欢考“生产者消费者问题用什么机制实现”。有一道经典选择题是这样的多个线程同时调用printf打印内容最终输出会不会混乱背景知识是printf内部有缓冲区且stdout被设计为线程安全的在glibc的很多实现中通过加锁保证但同一个线程多次调用printf的输出不保证连续。所以“不会混乱但可能交织在一起”是更准确的描述。这种细节题没有亲手写过并发程序的人很难答对。4.2 死锁四个必要条件必须张口就来死锁题是操作系统部分的稳定送分题前提是你真的记住了互斥条件请求与保持条件不可剥夺条件循环等待条件笔试常考的是“下列哪种策略可以预防死锁”。比如打破互斥让资源可共享但很多资源本质上无法共享不现实。打破请求与保持资源一次性申请即静态分配。打破不可剥夺允许强行剥夺资源。打破循环等待资源编号并按序申请。这里有一个特别容易踩的坑银行家算法是“避免死锁”而不是“预防死锁”。笔试选项里如果把“银行家算法属于预防死锁”说成对的千万别选它。这个区分当年让我丢过分写下来提醒后来者。4.3 Linux常用命令笔试里的隐形得分点美团笔试的Linux题目不算多但每年都会有一两道。常见题型是给出一个日志文件要去重统计每个IP出现的次数用什么命令组合找出某个目录下占用空间最大的前5个文件。把某个进程按照CPU使用率排序。第一种场景的标准答案是cat access.log | awk {print $1} | sort | uniq -c | sort -rn | head -n 10这个组合看起来基础但考察的点很密集awk取出IP、sort排序让重复项相邻、uniq -c统计次数、sort -rn按数字逆序排序、head取前几行。每一环都不能漏。第二种场景常用命令是du加sortdu -ah /var/log | sort -rh | head -n 5这里的坑在于du -h的输出比如1.5G用sort按字典序排会出错所以要用sort -rh让G/M/K按照人类可读的数字大小排序而不是按字符串排序。实际在工作中这类命令组合几乎每天都会用到。笔试不要求你记住每一个参数但常见场景要能熟练写出来。建议平时用虚拟机多练几遍形成肌肉记忆。5. 数据库与设计题容易拉开分差的“应用题”美团2016年那套题里有一道很典型的SQL编写题和一道简答设计题。我印象最深的是SQL题看起来很简单但评价标准里有很多隐藏细节。5.1 SQL基础慢查询优化题的核心是EXPLAIN有一类经典SQL题给定一个订单表order(id, user_id, order_time, amount)查询每个用户最近一笔订单。刚一看很简单但如果你写成SELECT user_id, MAX(order_time) FROM order GROUP BY user_id;这是不完整的——因为需求通常是“返回每个用户最近一笔订单的完整记录”而不只是时间和用户ID。一个标准做法是用窗口函数SELECT user_id, order_time, amount FROM ( SELECT user_id, order_time, amount, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY order_time DESC) AS rn FROM order ) t WHERE rn 1;但2016年的时候很多数据库还不支持窗口函数MySQL 8.0之后才内置支持所以常见的答案是关联子查询SELECT o.* FROM order o JOIN ( SELECT user_id, MAX(order_time) AS max_time FROM order GROUP BY user_id ) t ON o.user_id t.user_id AND o.order_time t.max_time;这里有个隐藏坑如果同一个用户在同一秒产生了多笔订单这个SQL会返回多行。面试官会追问“怎么保证唯一性”答案往往是加一个id排序条件或者先按user_id, order_time, id联合排序再去重。笔试遇到SQL题我的经验是先把业务约束理解透再看能不能用窗口函数最后检查数据倾斜和重复记录。这三个步骤走完基本能写出面试官满意的答案。5.2 索引设计从一道选择题聊到实战选择题常考在WHERE、ORDER BY、GROUP BY中哪些字段适合建索引答案是WHERE的条件字段和ORDER BY的排序字段适合GROUP BY的字段也能通过索引避免文件排序。有一个常见误区对性别这种区分度很低的字段建索引效果往往很差。因为区分度太低用索引反而会增加回表开销SQL优化器可能直接走全表扫描。这个知识点在美团笔试出现过选项也在实际工作中遇到过——一位同事给一个“用户状态”字段建了索引结果查询反而变慢了当时我们一起用EXPLAIN排查发现优化器估算出全表扫描代价更低压根没用那个索引。建索引的几条实操建议区分度高的字段优先。联合索引遵循“最左前缀”原则查询条件里必须包含最左字段。不要对频繁更新的字段建过多索引写性能会受影响。ORDER BY字段尽量与索引顺序一致避免文件排序。5.3 事务隔离级别脏读、不可重复读、幻读数据库简答题里美团很喜欢考“事务隔离级别”以及“每种级别下会出现什么问题”。标准四档隔离级别脏读不可重复读幻读Read Uncommitted可能可能可能Read Committed不可能可能可能Repeatable Read不可能不可能可能Serializable不可能不可能不可能一个容易被忽略的细节MySQL默认隔离级别是Repeatable Read但这不意味着它完全解决了幻读。InnoDB在Repeatable Read下通过间隙锁Gap Lock和临键锁Next-Key Lock解决了大部分幻读问题但在某些场景下比如当前读的条件范围没有匹配索引幻读依然可能发生。当年笔试有一道题就问在Repeatable Read隔离级别下事务A先查询id100的记录不存在事务B插入id100并提交事务A再插入id100会发生什么答案是如果id是主键在RR级别下A插入时可能会触发主键冲突因为当前读被间隙锁阻塞后B已经插入成功了A再次尝试插入自然失败。这个场景如果没实际验证过很难答对。备考时我建议把这个场景用MySQL自带的客户端亲手做一遍把隔离级别调来调去看看每个级别下事务的可见性行为。这是理解事务最直接的方式。6. 语言基础与概率逻辑题看似不算分实际很拉分这类题在整套卷子里占比不大但往往是决定你是否进入下一面的关键。因为算法题大家都在刷语言细节和概率题却往往是最能拉开差距的部分。6.1 C/Java语言基础常考“底层原理”而不是语法糖美团笔试的语言基础题通常不是考语法而是考“为什么这样设计”。比如C的虚函数表当一个类含有虚函数时对象的内存布局里会有一个指向虚函数表的指针虚函数表存放在只读数据段。多继承情况下的虚函数表会更复杂。笔试选择题可能会问“虚函数表是编译期生成还是运行期生成”——答案是编译期生成运行期通过对象头部的指针找到。Java部分常考的包括HashMap在JDK 1.7和1.8的区别1.7使用头插法可能产生循环链表1.8改为尾插法并引入红黑树当链表长度超过8且数组长度大于等于64时树化。ConcurrentHashMap在1.7是分段锁Segment1.8改为CAS加synchronized锁节点。JVM内存分区堆、栈、方法区、程序计数器。其中方法区在1.8之后改为元空间Metaspace使用本地内存。这部分的备考方法没有捷径只能靠多刷题、多看源码分析文章然后自己画一遍内存模型图。我记得自己当时画了大概二十多张图把HashMap的put流程、红黑树的左旋右旋、JVM内存分配从头到尾过了一遍笔试时遇到相关的题基本上秒选。6.2 概率统计题经典题目反复出现有一道高频概率题两个人约定在某个时间段内到达见面地点先到的人等15分钟求两人能见面的概率。这类题是典型的几何概型两个独立均匀分布变量在坐标平面内画出可行区域计算面积比例即可。解法思路大概是设甲到达时间为X乙到达时间为YX和Y都服从[0, 60]的均匀分布。两人能见面等价于|X - Y| ≤ 15。在60x60的方形区域中可行区域是中间带状区域概率等于1 - (45/60)^2 6/16 0.4375。这种题美团比较喜欢出因为能看出候选人有没有数学建模的直觉。备考时把几何概型、全概率公式、贝叶斯公式全部过一遍基本就能覆盖了。6.3 逻辑推理题留到最后再做逻辑推理题在笔试中属于“高投入低产出”的题型如果时间不够可以直接放弃。但有一套通用的思路先找矛盾项再画关系图最后代入验证。这种题考察的是思维清晰度技巧性不强但很吃考场心态。我自己的策略是这类题统一放到最后20分钟做保证前面的算法题和SQL题拿到分数。7. 复盘与实践从2016真题到今天的面试准备思路聊了这么多考点最后说点实际的准备建议。这套2016年美团笔试题放在今天看部分知识细节已经过时比如HashMap底层、MySQL窗口函数支持情况但核心考察逻辑没有变基础扎实、能落地、思路清晰。7.1 刷题优先级算法永远第一但不要只刷算法我的建议是准备校招笔试的时候时间分配可以按5:3:2来安排——50%时间刷算法题30%时间补计算机基础20%时间做模拟题和复盘。算法题是硬通货但只靠算法过关是不够的。美团这类公司非常看重候选人有没有完整的知识体系因为实际业务里遇到问题往往是“网络OS数据库”的混合场景。7.2 模拟考一定要做很多同学刷题时候很厉害一上笔试就紧张时间分配失衡。建议在正式笔试前两周找一套往年的真题严格按两个小时来模拟。考完之后不要只看对错要把每道错题的知识点整理成笔记尤其是那些“因为没看清题目而丢分”的题。这种错误在真实笔试中代价极大——一道选择题可能直接决定你是否进入下一个环节。7.3 保持“为什么”的习惯备考期间最忌讳的就是背答案。看到一个题的解法先问自己为什么这样做是对的有没有反例能不能推广到更一般的情况我在准备美团这套题的时候有一道链表题看了别人的解法觉得“很妙”但三天后再做又不会了。原因就是当时没有真正理解它为什么对只记住了几个步骤。后来我强迫自己把每道题都讲给旁边的同学听能讲明白的才算真正的掌握了。这种“自己讲一遍”的方法后来也成了我做技术复盘的习惯。无论面试还是实际工作把问题向别人解释清楚的过程往往就是彻底想通的过程。最后分享一个我个人的实操体会笔试前一个晚上不要再看新题了。把以前做错的题目快速过一遍把容易混淆的概念比如HTTP 301和302、TCP TIME_WAIT、HashMap的树化阈值在脑子里像过电影一样过一遍然后早点休息。考场上状态的稳定性比多背一道题重要得多。记住一句话笔试考的不是你的智商上限而是你准备的下限。把下限提上来结果就不会差。
返回列表