ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

2020美团后台笔试题全解析:算法、系统设计与高并发场景实战

2020美团后台笔试题全解析:算法、系统设计与高并发场景实战 1. 2020美团后台笔试题整体画像与考点分布1.1 题型结构与技术栈倾向说到2020年美团校招后台开发方向的笔试题我第一个感觉是它不像很多公司那样纯粹考“会不会刷题”而是明显带着业务味道。那一年因为特殊情况笔试基本都搬到了线上时间压缩得比较紧一般是一场笔试涵盖选择题、编程题有的批次还会夹带一两道场景设计题。候选人需要在90到120分钟里完成节奏相当快。从技术栈倾向来看美团后台大量使用Java但笔试环节并不强制你只用JavaC、Go通常也能提交。我认识一个同学全程用Go写也能通过用例。关键是你对语言本身的掌握要足够熟不要因为伪代码写得太high就忽略边界条件。选择题覆盖得比较杂Java内存模型、JVM调优基础、Spring的Bean生命周期、MySQL索引、Redis持久化、TCP拥塞控制、Linux常用命令。这些不是背诵就能出高分需要真懂原理。题型结构大致可以这样概括20到30道单选题或多选题2到3道在线编程题部分批次的简答题会要求你设计一个接口或排查一个线上问题。美团笔试比较有意思的地方是编程题经常会给你一个“美团风格”的背景比如外卖订单分配、商家评分排序、红包金额拆分。这其实是把算法题用业务场景包装起来考点还是那些但如果你不会把问题抽象成模型很容易被题目描述绕进去。1.2 核心考点权重对比我自己复盘过这几年美团笔试的考点也问过不少上岸的同学大家反馈比较一致数据结构和算法是绝对大头其次是数据库和场景设计接着是操作系统、网络和Linux。考点方向估算占比典型问法数据结构与算法30%手写LRU、链表反转、二叉树遍历、动态规划状态转移数据库15%索引为什么用B树、事务隔离级别怎么选、分库分表策略系统设计/场景题15%设计外卖红包系统、设计配送调度策略、库存扣减方案计算机网络12%三次握手可以两次吗、HTTP/2多路复用原理操作系统12%进程和线程区别、死锁必要条件、虚拟内存好处Linux与编程基础10%线上CPU飙高怎么排查、grep/awk使用、静态变量存储位置其他智力题/逻辑题6%概率题、逻辑推断、简单数学建模从权重能看出一个信号后台开发岗位并不要求你成为精通某一块的“专才”反而希望你有全局视野。美团的核心业务是本地生活服务外卖、到店、酒旅、配送这些系统都是典型的高并发、分布式场景面试官会通过笔试题提前筛选那些“系统思维”还不错的候选人。所以备考时不要只盯LeetCode还要有意识地训练自己从业务问题里提炼技术方案的能力。2. 典型算法题拆解编程题为什么难在“业务建模”2.1 常考算法知识点与刷题策略美团笔试题里的算法部分整体难度在互联网大厂中属于中上。最高频的知识点是数组和链表操作、二叉树相关遍历、哈希表、动态规划、贪心、二分查找、字符串处理、排序与TopK、并查集。图算法和线段树这类高级考点出现频率不高但一旦出现就是压轴题。刷题策略上我不建议上来就刷难题。先把基础的数据结构实现过一遍尤其是手写链表反转、判断链表是否有环、二叉树前中后序遍历、层序遍历、二分查找的各种变体。这些题看起来简单但笔试环境里没有IDE提示容易在边界条件上翻车。我自己的习惯是用纸笔先把核心逻辑写一遍再敲到编辑器里跑测试用例。这个习惯能有效减少提交时的低级错误。动态规划和贪心每年必考。美团很喜欢考近似于“背包”“区间调度”的变体题解决思路不会超出常见DP模型但会套一层业务壳。比如“多个外卖订单有取餐时间窗口和超时惩罚如何选择订单使总收益最大”本质上是一个带权区间调度问题。如果你能在看到背景后迅速识别出是DP就已经赢了一半。2.2 真题模拟外卖订单分配问题这里我模拟一道很有美团风格的编程题给出一张网格地图地图上有若干商家、用户、骑手。每个骑手一次最多配送k个订单每个订单包含取餐点坐标和送餐点坐标。要求给骑手分配订单使所有骑手总配送距离最小。这道题综合了图论、贪心和组合优化笔试版本通常会简化成静态分配。如果当作贪心题来写思路很直接按订单的时间紧迫程度排序然后依次为每个订单找当前距离最近的骑手更新骑手位置。代码大概长这样public void greedyAssign(ListOrder orders, ListRider riders) { orders.sort(Comparator.comparing(Order::getDeadline)); for (Order order : orders) { Rider best null; double bestCost Double.MAX_VALUE; for (Rider rider : riders) { if (rider.currentOrders.size() rider.capacity) { continue; } double cost dist(rider.pos, order.pickup) dist(order.pickup, order.delivery); if (cost bestCost) { bestCost cost; best rider; } } if (best ! null) { best.assign(order); best.pos order.delivery; } } }这种近邻贪心能过一部分测试用例但不算最优。如果题目要求全局最优需要转成二分图最小权匹配把订单集合和骑手可接单状态建模成匹配关系用KM算法或最小费用最大流求解。笔试里不建议真的实现KM算法除非你非常熟练否则写复杂算法的出错概率远高于拿到的分数。比较稳妥的做法是先写一个可行解再在题目要求的范围内做局部优化。面试官更看重你能否快速给出一个合理方案而不是在45分钟内写出完美的最优解。2.3 真题模拟手写LRU缓存LRU缓存是后台岗位笔试题里的“常青树”美团也喜欢把它包装成“商家活动页面本地缓存”之类的场景。核心要求是实现一个get和put均为O(1)时间复杂度的缓存容量满时淘汰最久未使用的key。标准解法是哈希表加双向链表哈希表负责O(1)查找链表维护访问顺序。class LRUCache { private MapInteger, Node map; private int capacity; private Node head, tail; public LRUCache(int capacity) { this.capacity capacity; map new HashMap(); head new Node(); tail new Node(); head.next tail; tail.prev head; } public int get(int key) { if (!map.containsKey(key)) return -1; Node node map.get(key); moveToHead(node); return node.value; } public void put(int key, int value) { if (map.containsKey(key)) { Node node map.get(key); node.value value; moveToHead(node); } else { Node node new Node(key, value); map.put(key, node); addToHead(node); if (map.size() capacity) { Node removed removeTail(); map.remove(removed.key); } } } }我在笔试中见过不少同学把LRU写成LinkedHashMap一行版但在不让用工具类的笔试题里这样会直接丢分。建议平时就手写一遍链表节点和四个基础操作addToHead、removeNode、moveToHead、removeTail。写的时候注意null判断和删除节点时双向指针都要更新。这类题考察的不是算法难度而是代码基本功和内存意识。3. 后台开发场景题与系统设计题目实战攻略3.1 从“外卖派单”看分布式系统考点美团业务天然带有多地多中心、高并发、实时调度等特点所以笔试中系统设计题特别喜欢围绕“外卖派单”“骑手路径规划”“商家订单推送”来出。这类题看起来是开放式的其实是在考察你对分布式系统基本组件的理解服务拆分、消息队列、缓存、数据库分片、容灾降级。以“外卖派单”为例核心指标是订单从用户下达到骑手接单的时长。要降低这个时长不能只靠一个派单算法还要考虑位置服务的高并发读取、订单状态的实时推送、骑手App的长连接维护。答题时我建议先画数据流再拆模块用户端下发订单订单服务写主库同时推送消息到MQ派单服务消费消息后结合骑手实时位置做匹配匹配结果再通过推送服务发给骑手。这里用到MQ是为了削峰填谷防止高峰期直接打爆数据库。另一个常考考点是“如何保证多个服务之间的数据一致性”。比如订单状态已支付但派单服务没有收到消息用户就会看到订单一直等待。笔试题不会要求你写完整代码但你必须能说出至少两种方案本地消息表加定时任务扫描或者引入分布式事务框架。要讲清楚各自的优缺点以及为什么互联网公司更倾向使用最终一致性而不是强一致。3.2 高并发下“库存扣减”题的标准思路库存扣减是后台开发笔试题里出现率极高的经典场景美团也会把它改造成“秒杀优惠券库存”“一秒内限量特价菜库存”。这类题的核心矛盾是高并发下如何保证不超卖同时保持接口响应速度。标准思路有三种层次。第一种是数据库乐观锁在库存表中加一个version字段更新时带上version如果更新影响行数为0说明冲突重试或返回失败。这个方案实现简单但高并发下会大量重试数据库压力很大。第二种是用Redis做预扣减先用DECR命令扣减库存扣减成功后再异步落库最终以数据库为准。Redis单线程模型天然不会有并发扣减超卖问题但要注意Redis和数据库的一致性。更完整的方案是“Redis MQ 定时对账”。用户请求先走到Redis扣减库存扣减成功则返回“抢购中”同时投递一条消息到MQ由消费端异步更新数据库中的库存和订单状态。短信通知用户时再根据数据库实际状态做最终一致性校验。我在面试中回答这类题时一定会补一句所谓“不超卖”指的是数据库最终不出现负数而不是Redis瞬间不能扣到负数。这个理解很重要很多候选人一上来就说“Redis保证一定不超卖”但没解释最终归档环节。3.3 场景题答题框架先拆功能再定技术选型如果笔试里有一道完整的设计题比如“设计一个美团外卖优惠券系统”不要上来就写代码。阅卷人看的是你的思考过程。建议按四步走功能拆解、容量估算、存储设计、接口定义。功能上优惠券系统至少要包含发券、领券、核销、过期处理、风控。容量上假设高峰期每秒有1万人领券一次领券操作涉及查询用户资格、扣减券模板库存、写入用户券表写QPS大约要支持1万以上读QPS可能到5万。存储上券模板库存和用户券是两种表前者用MySQL高并发读写要加Redis缓存后者量大会按月分表。接口上要定义领券接口、查询券列表接口、核销接口同时考虑幂等设计同一用户同一批次领券不能因为网络重试领两次。这个框架几乎可以套用到所有场景设计题。面试官看到你能从流量估算推导出分库分表、缓存、消息队列这些组件才会觉得你是真的做过后台开发而不是只背了八股文。4. 数据库、网络与操作系统必须掌握的基础题4.1 数据库索引与事务隔离的典型问法美团笔试题里数据库部分非常务实最常出现的就是索引和事务。为什么索引用B树而不是红黑树因为B树在磁盘IO场景下有更高的扇出三层B树就能存储千万级数据而红黑树高度更高磁盘访问次数更多。同时B树叶子节点通过链表串联非常适合范围查询。这种题不能只答“查询快”要从磁盘IO和数据结构特性两个角度解释。事务隔离级别也是必考。四个级别分别对应不同问题读未提交可能产生脏读读已提交解决脏读但不可重复读可重复读解决不可重复读串行化解决幻读但性能极低。美团大部分业务订单库默认使用可重复读但如果你设计的是高并发扣减库存表还要明白间隙锁带来的性能影响。笔试题里经常给一个场景问“某隔离级别下两个并发事务的最终结果是什么”你需要手推执行顺序。还有一个高频点是Redis的持久化机制RDB和AOF的区别。RDB是定期快照恢复快但可能丢数据AOF是追加日志数据更安全但文件大恢复慢。笔试题问“如果Redis宕机后如何保证不超卖”答案不是靠Redis持久化而是靠数据库扣减兜底。把Redis当缓存、把MySQL当主存储这个角色分工要想清楚。4.2 网络与操作系统必背高频点网络部分常考TCP和HTTP。三次握手能不能改成两次不能因为两次握手无法防止历史连接请求突然到达服务端导致资源浪费。四次挥手中的TIME_WAIT为什么存在为了保证最后一个ACK能到达对端同时让旧数据包从网络中消失。HTTP/2相比HTTP/1.1的核心改进是多路复用、头部压缩、二进制分帧这些可以直接联系到“地图瓦片加载”“骑手长连接推送”场景中。操作系统重点在进程线程、死锁、内存管理。进程和线程的经典区别是进程是资源分配的基本单位线程是CPU调度的基本单位同一进程的线程共享地址空间但进程之间相互隔离。死锁四个必要条件依次是互斥、持有并等待、不可剥夺、循环等待。笔试时会给出多个资源分配情况让你判断是否死锁这时候要会画资源分配图。Linux命令的考察经常是“线上接口变慢你如何排查”。我在答题时会写先top看CPU和负载再用free -h看内存iostat看磁盘IO然后jstack看线程栈找到CPU占用最高的线程netstat或ss看连接数是否打满。美团这种场景题本质是在考察你遇到线上故障的定位思路是否清晰而不是真让你写一堆参数。4.3 基础题答题模板与常见误区很多同学在笔试中失分不是因为不会而是因为答题太乱。选择题还好简答题如果不分点阅卷人很难一眼抓到重点。我的习惯是“先结论后原因再举例”。比如问到“为什么要分库分表”先回答“因为单库连接数和磁盘IO达到瓶颈”再展开垂直拆分和水平拆分的区别最后以“订单表按用户ID取模拆成16个库”作为例子。常见误区有两个。一个是不看题目要求的数据规模就回答“用Redis缓存解决一切”。如果题里说月活只有几千那单库MySQL就是最优解引入Redis反而增加复杂度。另一个误区是谈到分布式一致性就只会说“用分布式事务”但分布式事务会严重降低吞吐有时候业务允许短暂不一致应该优先考虑最终一致性。记住笔试里“方案合理”比“方案高级”更重要。5. 备考节奏与一手经验5.1 刷题节奏与资料选择如果你是准备秋招的后台开发同学我的建议是在笔试前至少留出两到三个月。第一个月按数据结构分专题刷LeetCode不用贪多每天3到5道中等题重点把模板题写熟。数组、链表、哈希表、二叉树、动态规划这几个方向必须保证正确率在80%以上。第二个月开始刷牛客网上的互联网历年真题尤其是美团、字节、阿里的后台卷目的不是为了遇到原题而是适应赛场节奏。第三个阶段是“场景题专项训练”。可以找一个高频题列表设计短链系统、设计秒杀系统、设计外卖配送系统、设计关注关系系统。每个题都按我前面说的“功能拆解、容量估算、存储设计、接口定义”四步法写一版答案。我会建议同学们把答案写成带子标题的Word文档方便后面复习。这个阶段不要只动嘴要真写出来写到纸上和想到是两回事。资料方面我觉得不需要囤太多。LeetCode hot 100加上牛客真题再加一本《Java并发编程的艺术》或《深入理解计算机系统》选读已经足够应付笔试。不要花大量时间背冷门题美团笔试的算法题基本不会超出“中等难度偏上”这个区间。5.2 笔试现场要注意的细节2020年线上笔试流行之后很多同学都吃过设备问题的亏。笔试前一定要提前一天测试摄像头、麦克风、网络稳定性最好准备一条有线网络备用。在浏览器里提前登录笔试平台把键盘切到英文输入法。我见过有同学因为输入法弹窗导致页面卡死最后白白浪费五分钟。时间分配上如果选择题感觉拿不准不要死磕。一道题思考超过两分钟就先标记跳过编程题优先做有把握的前两题。因为美团笔试的判分一般按照通过用例的百分比来给分哪怕只能用暴力解通过20%的用例也比留空强。建议编程题先写一个暴力版本保底再优化成正解。这个方法虽然听起来笨但在真实考试中非常有效。答题过程中一定要留意题目给出的数据范围。数据量在10的5次方以上基本意味着需要O(n log n)或O(n)解法如果看到你写的代码复杂度是O(n^2)大概率会超时。反过来数据量很小的时候用简单的暴力枚举完全没问题不用非要套复杂的算法。5.3 项目经历如何为笔试加分笔试虽然是考知识但如果你项目经历里有和美团业务相似的场景会在后续面试环节被反复问到。如果你做过秒杀项目就把库存扣减、幂等、限流这些细节嚼透。如果你做过外卖类项目就去研究一下真实外卖平台是怎么做骑手路径规划的。这些前期积累会在面试时变成你的优势。我自己复盘下来最值得投入时间的不是背八股文而是把项目中每一个技术细节都问一遍“为什么”。比如为什么用Redis不用本地缓存为什么消息队列选RocketMQ而不是Kafka为什么数据库表要冗余订单状态字段这些问题是笔试题的延伸也是面试官最爱追问的方向。当你把这些问题的答案从“背”变成“自己的理解”时笔试中的简答题基本不会失分。最后分享一个我从失败中得来的经验笔试前一周不要再看新题而是把所有做过的错题和场景题笔记重看一遍。我在2020年秋招时就因为贪多考前还在刷难题结果笔试时脑袋空空连LRU的边界条件都写错了。从那以后我就明白了校招笔试考察的是稳定输出能力不是极限冲刺能力。你能在限定时间内把自己会的题不丢分拿到就已经赢了大部分人。
返回列表