多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

美团2023校招笔试编程题全解析:真题拆解与备战策略

美团2023校招笔试编程题全解析:真题拆解与备战策略 每年到了校招季总会有大量同学来问我同一个问题“美团笔试到底考什么该怎么准备”说实话美团2023校招笔试第1场编程题的难度在各大厂里属于中坚水平——没有字节那种动不动就上困难题的压力测试也没有某些国企那么放水。但它最大的特点是题量大、时间紧、题目包装得很“业务”。如果你只会刷LeetCode而不习惯读长题干第一场笔试很容易翻车。这篇文章我就结合2023校招第1场笔试的真题风格从试卷结构、核心考点、完整解题思路到备赛策略一次性给你拆透。无论你是准备来年校招的在校生还是想跳槽的社招选手这篇都能帮你少走不少弯路。1. 整体印象第1场笔试的试卷结构与时限压力1.1 题目构成与分值分布美团2023校招技术岗笔试统一采用牛客网平台第1场编程题部分是整套试卷中区分度最高的环节。从题目数量上看一般是4道编程题总分100分每道题分值不一定完全均等——通常前两道偏基础每道20分左右后两道难度攀升每道30分左右。这里有一个很关键的细节美团的编程题并不像ACM那样只追求AC而是按通过的测试用例比例给分。也就是说如果你暴力解法能过掉30%的用例也能拿到相应比例的分数。这个机制对基础薄弱的同学其实是个缓冲但同时意味着死磕一道题不如先拿稳所有题目的保底分。时间方面编程题总时长一般控制在90到120分钟加上选择题部分整场笔试的节奏相当紧凑。我见过太多同学在第1题上花40分钟死磕最优解结果后面三道题只能匆匆写下“题意理解”就交卷。这是笔试的大忌。1.2 平台环境与输入输出陷阱美团笔试的代码环境是牛客的在线编辑器支持C、Java、Python等主流语言。但有几个细节值得提前适应输入输出全部走标准IO不支持核心代码模式需要自己处理输入解析。很多平时用LeetCode函数模式做题的同学第一次上牛客会懵怎么还有EOF判定的坑数据量级往往给得很大不要指望O(n²)能跑过全部用例但O(n log n)通常是安全线。平台支持自测但自测用例有限边界条件要靠自己补比如空数组、单个元素、极大极小值。我在辅导学生时反复强调提前一周熟悉牛客的输入输出模式至少做10道牛客题集里的题笔试时你会感谢这个习惯。2. 真题拆解四道代表性编程题的完整解题链路下面我根据美团2023校招第1场笔试的常见题型整理了四道最具代表性的真题题目为同风格复现非官方原文但考点和难度与真实考试一致并给出完整拆解。2.1 第1题字符串变换回文串的最小操作次数题目描述给定一个只包含小写字母的字符串s每次操作可以将任意一个字符改为任意小写字母。请求出将s变成回文串所需的最少操作次数。输入描述一行字符串s长度1 ≤ |s| ≤ 10^5。输出描述一个整数表示最少操作次数。思路分析这道题属于典型的“简单题送分题”核心考察对回文串对称性的理解。回文串要求第i个字符和第len-1-i个字符相同因此我们只需使用双指针从两端向中间扫描凡是遇到对称位置字符不同的就修改其中一个使二者相等。每个不同位置只需要1次操作统计总数即可。这里需要注意修改哪一个字符其实不重要因为题目只管最终是否相等不限制具体改成什么字母——除非题目额外要求字典序最小第1场没有这个要求但第2场有类似变体后面会讲。参考代码Pythondef min_ops_to_palindrome(s: str) - int: left, right 0, len(s) - 1 ops 0 while left right: if s[left] ! s[right]: ops 1 left 1 right - 1 return ops s input().strip() print(min_ops_to_palindrome(s))复杂度分析时间复杂度O(n)空间复杂度O(1)。对于1e5的字符串这几乎是瞬时完成的。易错点与扩展如果题目改成“每次操作可以将一个位置的字符改成任意小写字母求变成回文串的最小操作次数”当前解法正确但如果改成“只能用相邻交换的方式变成回文串”那就是另一道经典题——需要先判断能否构成回文再用贪心计算最小交换次数。在真实笔试中要注意题目描述里到底允许哪种操作一字之差解法天壤之别。2.2 第2题外卖配送区的订单调度区间选点问题题目描述美团外卖的配送区域内有n个订单每个订单有一个可配送时间区间[L_i, R_i]。一个骑手在一个时间段内只能配送一个订单。问至少需要多少个骑手才能覆盖所有订单输入描述第一行一个整数n1 ≤ n ≤ 10^5接下来n行每行两个整数L_i, R_i1 ≤ L_i ≤ R_i ≤ 10^9。输出描述一个整数表示最少需要的骑手数量。思路分析这道题的经典模型是“区间重叠最大深度”问题。把它想象成现实中的会议室预定每个订单是一个会议时间是唯一资源同一时刻只能开一个会如果所有会议的时间是固定的我们需要多少间会议室才能容纳全部会议答案是同一时刻最多有多少个区间重叠就需要多少个骑手。怎么求最大重叠数两个思路差分数组将所有区间的左端点1右端点后一位-1注意是R_i1的位置-1因为R_i时刻骑手完成该订单后可以接下一个订单然后做前缀和求过程中的最大值。扫描线优先队列按左端点排序用优先队列维护当前区间右端点的最小值。当新订单加入时如果当前最早的结束时间 ≤ 新订单左端点说明有骑手空闲弹出该结束时间否则需要新增骑手队列大小就是骑手数。第1场笔试中数据范围给到了1e5且L_i可达1e9说明不能用数组做差分必须用TreeMap或排序扫描线。参考代码Python 排序扫描import heapq n int(input()) orders [] for _ in range(n): l, r map(int, input().split()) orders.append((l, r)) # 按左端点排序 orders.sort(keylambda x: x[0]) min_heap [] # 存储当前被占用的骑手的结束时间 max_riders 0 for l, r in orders: # 如果最早结束的骑手在l时刻已经空闲直接复用 if min_heap and min_heap[0] l: heapq.heappop(min_heap) heapq.heappush(min_heap, r) else: heapq.heappush(min_heap, r) max_riders max(max_riders, len(min_heap)) print(max_riders)复杂度分析排序O(n log n)堆操作O(n log n)总复杂度O(n log n)完全可过。为什么不用差分数组因为L_i和R_i最大到1e9如果以坐标为下标开数组会爆内存。强行离散化也可以但扫描线优先队列写起来更直接且不容易错。这道题的经验是美团特别喜欢把经典算法包一层“外卖”“配送”“酒店预订”的业务外壳本质还是查“区间重叠最大值”。如果你在考场上能快速识别出原模型基本10分钟内能AC。2.3 第3题网格地图的最短配送时间0-1 BFS题目描述给你一个m行n列的网格每个格子要么是空地用0表示要么是障碍用1表示。骑手从左上角(0,0)出发要到达右下角(m-1,n-1)。每走一步上下左右耗时1分钟。骑手可以消耗1个金币破除一个障碍即这个格子可以走但任一路径上最多只能破除K个障碍。求最短配送时间。输入描述第一行三个整数m, n, K1 ≤ m, n ≤ 1000 ≤ K ≤ 100接下来m行每行n个整数值为0或1。输出描述一个整数表示最短配送时间如果不可达输出-1。思路分析这是一道“带状态的最短路”问题。如果直接把网格当成普通BFS遇到障碍就走不通了但允许“破墙”K次意味着状态不仅要记录坐标(x, y)还要记录“已经破了几堵墙”这个维度。标准的解法是0-1 BFS或Dijkstra最短路长度作为第一优先级破墙次数作为状态维度。状态定义为(x, y, broken)表示到达(x, y)且破墙broken次的最短时间。如果下一个格子是0代价是1状态变为(nx, ny, broken)如果是1且broken K代价也是1状态变为(nx, ny, broken 1)。注意普通队列BFS不适用于带权图但本题所有移动代价都为1所以依然是BFS只是状态从二维扩展成了三维。DFS在这道题里不可取因为求最短路且带状态约束DFS会陷入大量重复搜索必须用visited[0/1][m][n]来剪枝。参考代码Pythonfrom collections import deque m, n, K map(int, input().split()) grid [list(map(int, input().split())) for _ in range(m)] INF 10**9 # dist[x][y][b]表示到达(x,y)破墙b次的最短时间 dist [[[INF] * (K 1) for _ in range(n)] for __ in range(m)] dist[0][0][0] 0 dq deque() dq.append((0, 0, 0)) dirs [(1,0),(-1,0),(0,1),(0,-1)] while dq: x, y, b dq.popleft() if x m - 1 and y n - 1: continue d dist[x][y][b] for dx, dy in dirs: nx, ny x dx, y dy if 0 nx m and 0 ny n: cell grid[nx][ny] nb b (1 if cell 1 else 0) if nb K: nd d 1 if nd dist[nx][ny][nb]: dist[nx][ny][nb] nd dq.append((nx, ny, nb)) ans min(dist[m-1][n-1]) print(ans if ans ! INF else -1)复杂度分析状态数mn(K1)每个状态四条边复杂度为O(mnK)最坏1e6级别完全可跑。个人经验这道题是不少同学的“拦路虎”因为不熟悉“状态扩展”这种抽象方式。你可以在LeetCode刷一下“1293. 网格中的最短路径”几乎是同款题。美团这次笔试把K限制在100但m和n只有100其实留了很大的优化空间如果你能想到用堆优化那换成多组测试也不怕。2.4 第4题优惠券满减的最优凑单方案分组背包/状态DP题目描述你有一张满A减B的优惠券订单金额达到A后立减B元。平台上有n个商品每个商品只能选一次价格分别为p_i。你想选若干个商品使得总价不低于A且尽可能接近A在满足“不低于A”的前提下总价最小以便最大化优惠券价值。求这个最小总价如果所有商品加起来都不到A输出最少需要的补差价即所有商品总价与A的差值。输入描述第一行三个整数A, B, n1 ≤ A ≤ 10^51 ≤ B ≤ 10^41 ≤ n ≤ 100第二行n个整数p_i1 ≤ p_i ≤ 10^5。输出描述如果存在子集总价≥A输出最小的符合条件的子集总价减去B否则输出所有商品总价减去A即还需补多少差价。思路分析看到“每个商品只能选一次、凑出某个目标金额”第一反应是01背包。但这里的“目标金额”是A而非某个固定值——我们需要求所有能达到的大于等于A的总和中最小值。做法是用01背包的可行性DPdp[j]表示能否凑出金额j。商品的总价上限是sum(p_i)但为了节省内存可以只开A max(p_i)大小因为超过Amax_p的金额一定不是最优比如所有商品都选上可能超过A很多但一定可以扔掉一个高价值商品来更接近A这里需要仔细分析。关键逻辑自底向上更新dp数组从总价上限往下枚举找到第一个 A的不可达不对我们要找的是可达的最小J满足j≥A。参考代码PythonA, B, n map(int, input().split()) prices list(map(int, input().split())) total sum(prices) if total A: print(total - A) # 全部买上也达不到A还要补差价 exit() max_sum total dp [False] * (max_sum 1) dp[0] True for p in prices: for j in range(max_sum, p - 1, -1): if dp[j - p]: dp[j] True # 找到第一个 A 的可达金额 for j in range(A, max_sum 1): if dp[j]: print(j - B) break复杂度分析O(n * sum(p_i))。最坏情况下sum(p_i)可达100*1e51e7对于Python来说可能会比较吃力1e7次循环约1秒到数秒。在实际笔试中如果超时可以考虑用bitset加速。Python的int本身就是bitset可以用位运算优化bits 1 # 二进制第j位表示能否凑出金额j for p in prices: bits | bits p # 然后从第A位开始找第一个为1的位 for j in range(A, total 1): if (bits j) 1: print(j - B) break这种位运算01背包在Python里非常快1e7的规模也能轻松跑完。这是我在实际做题中发现的Python性能技巧建议收藏。3. 命题风格解剖美团笔试为什么这么出题3.1 从“业务包装”反推考点识别能力如果你横向对比各家大厂的笔试会发现美团一个非常突出的特点几乎每道算法题都会裹上一层业务外壳。第1题可能叫“订单备注纠错”、第2题叫“骑手排班”、第3题叫“智能配送路径规划”、第4题叫“红包凑单”。这个设计不是为了让题目更有趣而是为了考察你在信息冗余下抽取核心模型的能力。真实工作里产品经理给你提的需求永远是“用户希望下单更快”“骑手希望多接单”而你需要的正是把模糊的业务语言翻译成清晰的数据结构和算法模型。因此我强烈建议在刷题阶段不要只看题目给的函数名试着把每道LeetCode题改写成美团风格的业务题目。举个例子LeetCode 435“无重叠区间”可以改写成“美团门店的直播时段安排”——这些转化练习能显著提高你考场上读题的效率。3.2 难度梯度与“稳住基本盘”的得分策略从第1场到第3场美团笔试的难度曲线不是完全相同的。第1场通常被认为整体难度中等前两道题属于“LeetCode中等偏下”第三道“带限制BFS”属于中等第四道“背包类DP”属于中等偏上。这给了我们一个明确的策略优先保证第1、2题满分第3题尽量拿高分第4题优先写出暴力版本拿部分分再考虑优化。我在模拟考中统计过一组数据假如一个同学第1、2题各拿20分第3题暴力过60%用例得18分第4题空着总分58分。另一个同学每道题都只写暴力平均过50%用例总分也是50分。看起来差不多但前者有明确的时间规划实际考场上心态更稳超常发挥的概率更大。你要相信考试不只是考算法还考时间分配和心理素质。3.3 高频考点的优先级排序根据美团近3年笔试回忆题的统计包括2021、2022、2023校招编程题高频考点大致如下优先级考点类别典型题目出现频率1贪心 排序区间调度、活动安排、最少箭矢极高2动态规划背包/线性/区间01背包、最长上升子序列、买卖股票极高3BFS/DFS 状态压缩或三维状态迷宫最短路径、解锁密码、破墙路径高4双指针 / 滑动窗口无重复最长子串、字符串排列高5前缀和 / 差分子数组和、区间加、最大重叠区间高6二分答案 / 二分查找最小值最大化、搜索旋转排序数组中7图论并查集/拓扑/最小生成树连通分量、课程表、最小代价连路中低8单调栈 / 单调队列接雨水、滑动窗口最大值中低这张表是你在刷题阶段制定计划的重要依据。不要一上来就啃难题先把频率最高的几大块吃透性价比高得多。4. 实战演练从读题到AC的完整思维过程这一节我想直接用一道和美团风格高度相似的模拟题完整走一遍“读题→提炼模型→选算法→编码→验证”的链条帮你看着一个真实的思考过程。模拟题商户满减调度有n家商户参与平台活动每家商户提供一个优惠券面额为m_i元使用门槛为s_i元订单金额达到s_i即可使用优惠券。一个用户想找一家商户下单使得“订单金额至少为s_i”的同时折扣力度即m_i/s_i最大。如果有多个折扣力度相同的商户输出订单金额最小的那家的编号如果不存在满足条件的商户输出-1。n ≤ 10^5s_i ≤ 10^9。我的思考链路如下第一步看到“输出折扣力度最大的商户”这是一道“找最优”的题。最朴素的做法是遍历所有商户判断s_i是否在预算内这里题目虽然没说预算但我们可以假设用户有一个最大可支付金额限制比如预算B否则所有商户只要有s_i0就都能选问题就没意思了。实际笔试中会明确给出预算B这里我们补上预算上限B。完整题目补全给定预算B只能选择s_i ≤ B的商户找m_i/s_i最大者。第二步m_i/s_i是浮点数直接比较有精度问题。要避免浮点误差可以把分数比较转化为交叉相乘m1/s1 m2/s2 等价于 m1s2 m2s1。这一招在竞赛里叫“分数比较的整数化”很多同学忽略了结果被浮点精度卡了10分。第三步n有1e5直接排序后找第一个满足s_i≤B的不行因为折扣力度最大的不一定s_i最小。但我们可以将商户按s_i排序然后从预算B这个上限往下找由于我们要最大化m_i/s_i一种思路是遍历所有s_i≤B的商户直接取最大复杂度O(n)。这已经是线性的了完全能过。第一反应不用想复杂。第四步编码。注意细节输入输出格式商户编号从1开始。排序时如果有多个s_i相同的商户在比较折扣力度时要用整数乘法。这道模拟题的重点不是难而是想说明美团笔试里的很多题你不需要炫技老老实实遍历整数乘法规避浮点精度就能AC。在考场上稳定的解法比巧妙的解法更值钱。5. 备赛节奏三个月时间线规划与每日做题组合5.1 分阶段目标设定我见过太多同学在准备校招笔试时“东打一枪西打一炮”今天刷链表、明天刷二叉树、后天突然去扣难题结果三个月下来知识点全覆盖但每个都不深。这里我给出一个经过多人验证有效的三个月时间线第1个月基础期主攻数据结构和常见算法模板每天2-3道题按专题刷数组、链表、栈/队列、哈希表、二分、双指针、滑动窗口、贪心、基础DP、BFS/DFS。每个专题至少刷10道做到“看题能说出解法思路和复杂度”的程度。周末做一次整套模拟卷体验时间压力。第2个月强化期专项突破高频考点刷美团/牛客真题重点攻克DP背包、线性、区间和图论并查集、拓扑排序、最短路。每天至少1道中等题1道困难题困难题以DP和图论为主。每周做2套房鹿/牛客的真题模拟记录各题耗时和得分分析薄弱环节。第3个月冲刺期模拟考错题复盘快速编码训练每两天一套完整笔试模拟严格按照90分钟限时。复盘时重点分析哪些题耽误了超过20分钟为什么会卡住是模型识别不出还是编码速度慢还是边界条件漏了这个阶段不建议再大量刷新题错题重刷比刷新题的收益高得多。我强烈建议你维护一份“错题本”记录每道题的错误原因和一句话解法考前一周只看错题本。5.2 每日练习组合推荐如果你每天能挤出2小时我的建议是15分钟复习前一天的天错题本或者数据结构的模板比如快排、堆、并查集的代码。60分钟做2道题。一道中等题限时25分钟如果超时直接看题解一道困难题如果没有思路10分钟后看题解确保看懂后独立重写一遍。30分钟写题解笔记或整理模板代码重在记录思路。15分钟随机看一篇技术博客或源码解析拓宽视野。这里我要强调一下“限时”的意义笔试的算法能力 ≈ 在有限时间内识别模型 快速编码 自我验证。如果平时做题没有时间压力考场上很容易在“这题好像可以用二分好像不行试试DP”的犹豫中耗光时间。5.3 关于牛客平台使用的两点体会第一美团笔试用的是牛客网它的在线编辑器没有LeetCode那么好用没有自动补全、没有括号匹配高亮。建议你提前在牛客的“公司真题”模块里做几套题感受一下“手写代码”的感觉。你甚至可以故意关掉编辑器的自动缩进功能模拟考场的最差体验。第二牛客的判题系统对Python的递归深度是有限制的默认大约1000如果你用DFS递归处理链或树可能出现“本地能过线上爆栈”的情况。解决办法是要么改用迭代写法要么在代码开头加import sys; sys.setrecursionlimit(1000000)。这种小细节往往就是笔试卡你10分的隐形原因。6. 考场上的时间管理与典型失误复盘6.1 我见过最多的翻车场景每年笔试季结束我都会找一些同学复盘失败原因。下面这几类问题出现频率最高你可以对照检查困在第1题里出不来。觉得第1题一定要AC不然心态就崩了结果一道20分的题耗了40分钟。我建议每道题最多20分钟没有清晰思路就先跳过做完后面题目再回头补。输入输出格式处理错误。比如题目说“每行两个整数以空格分隔”但某些数据可能是多个空格甚至制表符。直接用input().split()处理多空格没问题但有些同学会去手动解析字符串反而出错。记住split()不传参数时会把连续空白符全部分割这是最稳的。不确定数据范围导致算法超时。很多同学看到n1e5还是写出了O(n²)的代码寄希望于“数据可能没那么强”。确实有些题的数据比较弱但不要赌这个。见到n的范围第一时间就要算出你的算法复杂度是否能过最坏情况。边界条件漏了。比如n0、空输入、K0不允许破墙、订单区间左端点等于右端点。这些情况往往能卡掉30%左右的测试用例。写完代码后一定要自己构造几个边界用例跑一遍。忘记输出-1的情况。很多题目都有“无解时输出-1”的要求但部分同学只关注了可行解路径漏判了不可达导致提交后莫名其妙扣分。6.2 我的考场答题顺序建议以4道编程题、90分钟为例我会这么做开考后先用3分钟速读全部4道题在草稿纸上写下每道题的核心考点和预估难度。不要在题面上停留太久只做分类。按“简单→困难”顺序做题。一般第1题送分第2题中等偏易这两道争取在25分钟内AC。第3题如果是有思路的留25-30分钟来写调试如果没有思路先写暴力版本拿部分分数立即跳到第4题。第4题通常是DP或复杂图论只留20分钟优先写暴力或特殊的子集枚举能过多少是多少。如果第3题很顺利可以把剩余时间全砸在第4题上。最后预留10分钟逐题检查输入输出格式、边界条件、变量类型比如用int是否会溢出Python无此问题。这个顺序的本质是你不可能全做对因此要先拿到最容易拿的分数再用剩余时间冲难题而不是反过来。6.3 一个实测有效的“5分钟止损法”我自己刷题和带学生时总结了一个“5分钟止损法”非常适合牛客这种限时场景读题后在草稿纸上写下考点、算法、复杂度和注意的边界条件。这个过程控制在5分钟内。如果5分钟过去还是没有任何思路立刻换题。如果有了思路但不知道怎么写说明对模板不熟也先跳过等做完其他题再回来看。这个方法能防止你陷入“感觉这题快想出来了再想5分钟”的恶性循环。考试不是证明你能解出所有题而是在单位时间内拿到最优分数。7. 写在最后的几点心里话关于美团2023校招笔试第1场编程题我能给出的最核心建议只有一句做真题但别只背真题。真题的作用是让你熟悉出题风格、考点分布和时间压力但如果只背那几道题的答案遇到稍微变个花样的题就束手无策了。我从2021年开始每年都带学生备战校招笔试一个明显的规律是那些最终通过笔试的人没有谁是靠“押题”获胜的全都是靠扎实刷题、总结模板、反复复盘练出来的。另外说句实在的笔试只是校招流程中的一环它固然重要但不是全部。很多人面试表现很好笔试分数差一点依然能拿到offer或者被调剂到其他部门也有笔试接近满分但面试沟通能力不行的人被刷。所以别因为一场笔试过度焦虑把它当成一次检验自己算法功底的体检就好。最后分享一个小技巧考前一周把常见算法的模板代码快排、归并、二分、并查集、Dijkstra、背包、BFS/DFS手动默写一遍不是复制粘贴而是手写。这个过程能让你在考场上写代码时更加从容少一些“这个函数怎么写来着”的卡顿。祝每一位正在备战的你都能在笔试中发挥出真实水平。
返回列表