ARTICLE DETAIL

资讯详情

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

饿了么算法岗笔试复盘:编程题与机器学习考点全解析

饿了么算法岗笔试复盘:编程题与机器学习考点全解析 2024年秋招投了饿了么的算法岗赶上了第一批笔试。当时看到“第一批”三个字心里其实有点没底——意味着没有前人的经验贴可以抄题型、难度、侧重点全是未知数。好在我平时刷题量和理论储备还算扎实笔试完整做下来加上考后马上复盘了三个多小时对一些题目和考点印象很深。这篇把我的真实经历和思考整理出来给后面准备外卖/本地生活方向算法岗的朋友做一个参考。先说结论饿了么这批算法岗笔试整体风格延续了大厂算法笔试题的“分量感”——题量不小、覆盖面广、编程题占大头但理论题也不是纯粹的送分题而是会结合业务场景去考。如果你只想靠刷LeetCode硬刚不补机器学习基础大概率会在后半程吃亏。1. 笔试全貌与整体策略1.1 第一批笔试题型结构回顾整场笔试大约两个小时出头题型分成三个大块单选题、多选题、编程题最后还有一道简答/开放题。整体给我的感觉是前面选择题考的是基础广度编程题考的是算法功底最后开放题考的是业务思维。三者权重不算均匀编程题占了差不多一半的分值这点和大多数互联网公司的算法岗笔试是一致的。单选题涉及的面很广数据结构栈、队列、堆、二叉树的遍历、排序算法的时间复杂度与稳定性、哈希冲突的解决办法、图论基本概念最短路径、拓扑排序、操作系统里进程线程的小知识点还有概率统计的送分题比如简单的期望计算。多选题则有相当一部分集中在了机器学习基础上——正则化项的作用、过拟合的解决手段、集成学习的基础概念等。这里要特别提醒一句饿了么这类本地生活公司的算法岗机器学习理论题比想象中要多。我当时心里预估的是“算法题占大头ML简单带过”结果做题时发现ML/统计相关的选择题占比可能超过三分之一。这也说明了一件事——本地生活业务里搜索、推荐、定价、调度这些核心场景全都高度依赖机器学习模型所以面试官希望考察候选人的理论基础是否扎实。1.2 时间分配与答题策略复盘两个多小时做下来我最大的感受是时间其实不算特别宽裕但如果你有清晰的策略是完全够用的。我的实际时间分配大概是选择题和判断题控制在40分钟以内编程题花70分钟左右最后开放题留了15分钟剩下几分钟回头检查选择题中拿不准的题。我的建议是优先做编程题再回头纠结选择题。原因很简单编程题分值高、每个用例按比例给分哪怕是部分通过也能拿到一定分数而选择题做错了就是零分纠结太久性价比很低。我当时先快速扫了一遍编程题发现四道题中有一道明显是“送分题”字符串处理类就先把它秒了再啃其他三道心理压力小很多。还有一个小技巧多选题宁少选不多选。很多多选的计分规则是“多选不得分、少选按比例得分”如果你不确定某个选项不要冒险选。这算是应试策略但很实用能帮你保住不少分数。2. 核心编程题拆解与实现复盘2.1 编程题考查方向整体分析这次的编程题一共有四道覆盖了字符串处理、二分答案/贪心、图论最短路、动态规划/背包这几类。说实话这个考点组合非常有代表性——它基本勾画出了外卖/本地生活业务中算法工程师日常要处理的几类问题文本匹配与匹配效率、资源分配与路径规划、成本最优决策。对比一下我刷过的其他大厂笔试题饿了么这批题目的特点在于并没有刻意堆砌特别偏难怪的数据结构比如后缀自动机、Link-Cut Tree这类基本不会出现而是更看重常见算法模型的灵活变通。比如其中一道题表面上是“在数组里找一个满足条件的位置”但加上一个单调性条件后立刻变成了“二分答案”的套路另一道题披着“骑手送外卖”的业务外衣剥掉外衣就是经典的最短路问题。所以我强烈建议准备阶段不要过度追求偏题怪题把常见算法模型吃透能一眼识别题目背后的考点比多刷一百道难题管用。2.2 字符串匹配与KMP算法实战四道笔试题里有一道是和字符串匹配高度相关的给定一个模式串P和一个文本串T要求在T中找到所有P的出现位置但加了一个限制条件——“允许最多一个字符不匹配”。这个变体很有意思直接暴力的做法是枚举T的每个位置然后逐位比对时间复杂度O(n*m)在字符串长度达到10^5级别时必然超时。第一时间的想法是KMP算法。KMP的核心思想是当匹配失败时利用next数组跳过已经匹配过的部分避免文本串指针回退。热词里提到“对于模式串Pabacaba其next数组”其实就是KMP最基本的考点——求出next数组然后在线性时间内完成匹配。但“允许一个字符不匹配”这个条件需要把KMP做一点扩展你可以在匹配过程中引入一个“已跳过次数”的计数最多允许一次失配后继续而不是直接回退到next数组。我写的时候的思路是对每个起始位置做“带容错的KMP匹配”同时用前缀函数进行加速。实际实现时可以枚举“跳过哪个字符”对每个位置做两次KMP分别从左右两侧匹配判断是否满足条件。优化后整体复杂度能压到O(n)级别。这类题大家平时准备时KMP的next数组推导一定要手推熟练因为笔试环境里调试不便对模板的熟悉程度直接决定你能不能快速写对。另外提一个我在考场上踩的小坑KMP的next数组有两种定义——一种是“最长相等前后缀长度”另一种是“最长相等前后缀长度-1”。刷题时我用惯了后者结果考场上写的是前者下标边界卡了好几分钟。建议备考时固定一种写法并把模板背到肌肉记忆的程度。2.3 图论最短路与业务场景变体另一道让人印象深刻的编程题是典型的Dijkstra算法变体。题目背景是有若干个配送站点每个站点之间通行的耗时不一样部分道路因为天气原因封路边权重置为无穷要求从仓库出发到某个目标站点的最短时间并且有一个特殊规则——如果连续走了K条边可以触发一次“加速”将下一条边的耗时减半。这道题如果只看表面很容易误以为是动态规划但仔细观察会发现只需要把“是否已连续走K条边”这个状态扩充到Dijkstra的节点状态里即可。标准的Dijkstra是维护“到每个节点的最短距离”这里我们维护的是“到每个节点、且当前连续边数为j的最短距离”。本质上就是一个分层图最短路问题。我实现时用的是优先队列最小堆 状态数组。优先队列里存的是(当前耗时, 当前节点, 当前连续边数)每次取出耗时最小的状态进行松弛。状态数大概是NKN是节点数K不超过10所以整体复杂度是O(NKlog(NK))完全在可接受范围内。这个题给我最大的启发是很多看似复杂的业务规则本质上只是在经典算法上增加一个状态维度。你不需要创造一个新算法但你需要有能力把业务约束翻译成算法状态。这个能力不是靠背题背出来的而是靠大量练习后形成的“题目拆解感”。备考时我建议把常见的状态扩展模型——分层图、状压DP、带权并查集——都过一遍考场上遇到变体就不会慌。2.4 贪心与二分答案综合题复盘还有一道题是典型的贪心二分答案结合有N个待配送订单每个订单有一个最晚送达时间骑手每次只能携带一个订单已知每个订单的配送耗时问至少要多少个骑手才能在所有订单截止前完成配送。这类“最小化资源数量满足时间约束”的问题标准解法就是二分答案。你先猜一个骑手数量mid然后写一个check(mid)函数判断“mid个骑手是否够用”。check里用贪心策略每个骑手按订单截止时间从早到晚排序后的顺序依次取单用一个最小堆维护每个骑手的“下一次空闲时间”每次把订单分配给最早空闲的骑手。如果最早空闲的骑手也来不及说明mid不够返回false。二分答案的边界条件需要特别小心。我第一次写的时候左边界设为1、右边界设为N但这个题因为每单只能带一个答案最小可能就是N每个骑手只送一单。如果截止时间非常紧张二分就算错了。后来我把右边界直接设为N并确保check函数在midN时一定返回true这样边界问题就绕开了。这道题考查的其实是两个算法思想的组合贪心负责构造可行性判断二分负责把最优化问题转化为判定问题。这是算法竞赛里非常常见、也非常实用的组合套路。建议备考时专门练一练这种“二分答案套贪心check”的题你会在很多大厂笔试里看到它的影子。2.5 动态规划/背包类题目的快速判断最后一道编程题是一道变种背包问题有若干种优惠券每种优惠券有价格和可抵扣金额并且每种券最多只能用一次求在预算为M的情况下最多能抵扣多少金额。这题的经典版本就是0/1背包但是在笔试里它套了一个“预算”和“抵扣”的双层业务包装。剥掉包装之后你会发现它其实是在问给定一堆物品每个有weight和value背包容量是M求最大value。标准解法是用一维数组做滚动DPdp[j]表示预算j能获得的最大抵扣金额转移方程是dp[j] max(dp[j], dp[j - cost[i]] value[i])。这道题本身不算难但有一个细节优惠券的价格可能为0。如果存在0元券滚动数组的遍历顺序会变得很微妙——如果还是从后往前遍历0元券可以被重复使用导致答案偏大。我当时把这个细节处理了一下先把0元券单独拿出来直接累加抵扣金额剩下的正价券再走背包DP。这个小坑也提醒了我笔试时越简单的题越要检查题目条件中是否有特殊情况。3. 机器学习与深度学习理论题复盘3.1 机器学习基础概念的考查方式这一批笔试的机器学习理论题覆盖面很广但整体难度中规中矩重在考察概念是否清晰。热词里频繁出现的“机器学习算法”“聚类算法”“KNN算法”在这些题中几乎都有涉及。举个例子有一道多选题问“哪些措施可以有效缓解过拟合”。选项包括增加L1正则化、增加L2正则化、增加训练数据量、增大模型复杂度、Dropout。前四个选项没什么争议但“Dropout”很多人不敢选因为Dropout更多是深度学习里的概念。其实从原理上讲Dropout通过随机丢弃神经元本质上是一种模型集成的近似对缓解过拟合非常有效所以这个选项也应该选上。这种跨知识域的考点如果你只盯着机器学习课本很容易丢分。还有一道题考了K-Means聚类的细节——“K-Means算法中簇中心更新的方式是”答案是对簇内所有样本取均值。这个考点看似基础但它的变形很容易出现在多选题里K-Means对初始中心敏感、K值需要预先指定、对离群点敏感这几个特性都是高频考点。我的感觉是这部分题的核心不在于你能不能背出公式而在于你是否真正理解每个算法背后的假设和局限。建议备考时对常见算法K-Means、KNN、决策树、逻辑回归、朴素贝叶斯的优缺点、适用场景、关键参数做一张汇总表考前快速过一遍。3.2 集成学习与XGBoost高频考点集成学习在近几年大厂算法岗笔试里几乎是“必考模块”这次也不例外。有一道多选题问“关于XGBoost以下说法正确的是”选项涉及XGBoost与GBDT的区别、正则化项的作用、对缺失值的处理、基学习器是否只能是CART树。这里需要特别提醒XGBoost的基学习器除了CART树还支持线性分类器所以“基学习器只能是CART树”这个选项是错的。另外XGBoost在目标函数里加入了叶子节点数和L2正则项来控制模型复杂度这也是它与传统GBDT的重要区别。还有一个容易被忽略的考点XGBoost能自动处理缺失值通过稀疏感知算法把缺失值分到增益更大的方向。热词里还提到了“XGBoost算法”和“BM25算法”。BM25是信息检索领域的经典排序公式我本来以为笔试不会涉及没想到在选择题里真的考了一道——问“BM25中IDF的计算方式和意义”。由此可见饿了么这类有搜索/推荐业务的公司对信息检索基础也有一定要求。备考时千万不能只盯机器学习和编程题搜索排序相关的经典算法也值得花时间过一遍。3.3 深度学习基础与优化器选择题深度学习部分笔试考得不算深但都是“默认你该知道”的知识点。比如有一道单选问“ReLU激活函数在输入为负时导数是几”答案是0。这种题本身不难但它是深度学习入门的基石如果你之前只搞传统机器学习没有接触过神经网络可能一时反应不过来。另一个印象比较深的是关于优化器的题给了一组训练loss曲线问哪一种情况说明学习率设置偏大。正确答案是“loss在下降过程中出现明显震荡”。这个考点很实际——在业务模型训练中学习率设置不合理是最常见的问题之一。热词里还提到了“强化学习算法”和“PID算法”前者在开放题中有所体现后者则是控制论中的经典算法也许在调度场景中会作为背景知识出现。我的建议是深度学习部分不需要背复杂的公式推导但要把激活函数、损失函数、正则化手段、常见优化器SGD、Adam、AdamW的基本原理和适用场景掌握清楚。这些知识点在笔试中的出题方式非常直白属于“复习到就能拿分没复习到就只能蒙”的类型。4. 开放题与业务场景题解析4.1 骑手调度场景算法如何落地业务这批笔试的最后一道开放题题目大意是高峰时段骑手运力不足、订单积压严重请设计一个调度策略使得订单平均配送时间尽可能短。这类题没有标准答案纯粹考察你能否将算法知识与业务场景结合。我的回答思路是这样展开的首先把问题拆成三个子问题——订单分配、路径规划、动态调度。订单分配可以建模为一个带时间窗的匹配问题用贪心或KM算法求近优解路径规划用Dijkstra/A*算法求骑手到店、到用户的最短路径动态调度则需要考虑实时新订单的插入这时可以借鉴“插入启发式算法”把新订单插入到骑手已有路径中边际成本最小的位置。热词里提到“粒子群算法原理”和“模拟退火算法”这两种启发式优化算法在这种场景中也有用武之地——当解空间太大无法精确求解时可以用粒子群或模拟退火寻找较优解。我在回答里提到如果订单数据量巨大且实时性要求极高可以先用规则引擎比如热词里提到的“规则引擎Drools的Rete算法实现原理”做粗筛再用优化算法做精排形成“规则算法”的混合策略。这种回答方式不一定是最优解但至少能展现出你有“把业务问题抽象成算法问题”的能力。我的经验是开放题不在乎你的方案是否全面而在乎你能不能展示出结构化的思考过程——从问题定义、拆解、建模到方案选型每一步都要有逻辑支撑。4.2 ETA预估与传统机器学习/深度学习建模还有一个简答题跟ETA预计到达时间相关——这类题在本地生活公司里出现频率很高几乎是必考题。问题是如果要预估骑手从A点到B点的配送时间你会怎么建模这个题的考察核心在于特征工程和模型选型。我在回答时提到ETA预估本质上是一个回归问题特征可以分成几类距离特征曼哈顿距离、欧氏距离、路网距离、时间特征是否为高峰期、是否节假日、骑手特征历史平均速度、当前负载、天气特征温度、降水、风力、商户特征出餐速度历史分位数。模型选择上我提到了两条路线一是用GBDT类模型XGBoost、LightGBM做离线训练优点是特征可解释性强、训练快、效果稳定二是用深度学习模型WideDeep、DeepFM捕捉高阶特征交互但需要更多数据且调参成本高。在实际业务里工业界最常用的其实是“GBDT排序/回归”的方案深度模型更多是锦上添花。最后我还加了一个点预估的不只是“平均时间”而是“时间分布”这样可以结合超时概率做更精细的调度决策。这个思路在面试中很加分因为它展示了你对业务指标超时率、用户满意度的敏感度。4.3 搜索排序与推荐中的算法应用搜索排序相关的题目也是一大重点。有一道多选题问的是“在电商/本地生活搜索排序中以下哪些特征适合作为排序模型输入”选项包括商品销量、用户历史点击率、商品与query的文本相关性、商品上架时间。这道题本身不算难但它的价值在于提醒你搜索排序绝不是只看相关性而是相关性、业务指标、个性化信号的融合排序。我在备考时专门整理了LTRLearning to Rank的三种训练方式Pointwise、Pairwise、Listwise。在大厂笔试里Pairwise和Listwise会以选择题的形式出现比如问“RankNet属于哪种训练方式”“LambdaRank的核心思想是什么”。热词里提到的BM25在召回阶段使用较多负责从海量商品中粗筛出候选集而精排阶段才会用到机器学习模型。所以“召回用BM25/DSSM精排用LTR模型”这条技术链路建议大家都记一下。此外热词中还出现了“腾讯视频CKey5.x算法PHP版”和“竞品分析”相关的内容。虽然这在饿了么笔试中直接出现的概率不高但搜索/推荐岗位需要你理解“客户端参数签名/加密”在反爬和算法安全中的作用。这类知识可以作为信息检索方向的扩展了解不需要深入钻研。5. 常见问题与排查技巧实录5.1 编程题作答时的环境与调试坑笔试使用的在线编辑器有一个很大的问题本地IDE里跑得好好的代码复制到在线编辑器后可能因为导入缺失直接编译失败。我在写Dijkstra那题时本地用了import heapq但在线编辑器默认不保留import语句提交后直接报错浪费了好几分钟排查。所以一定要养成写完代码后立刻检查import语句的习惯最好把常用库的import都写在代码开头。另一个坑是输入输出的格式。在线笔试要求严格按行读取、按行输出多一个空格都可能被判错。编程题里有一道需要输出浮点数题目要求“保留两位小数”我用print(round(ans, 2))输出结果判题系统期望的是字符串格式化的结果。大家最好统一用print(f{ans:.2f})这种格式化写法不要依赖round函数——round在某些边界条件下四舍五入行为和预期不一致。5.2 时间来不及时的得分策略如果做到最后发现编程题时间不够我的建议是先把最容易拿分的部分写出来不要追求完整解法。比如说题目要求输出所有满足条件的起始位置你暴力遍历能得部分分就先写暴力时间有余再优化成KMP或二分。很多在线判题系统是“按通过用例比例给分”的暴力实现只要能过几个小数据用例就比完全空着强。这个策略我在考场上实际用到了背包那道题我先写了一个不带0元券处理的版本通过了大部分用例然后回头检查时发现了0元券的坑补上后基本满分。先跑通、再优化、最后处理边界这个顺序在限时场景下是最稳妥的。5.3 理论题模棱两可时的做题技巧选择题里多选是丢分重灾区。我个人的经验是如果某个选项的描述里出现了“绝对”“一定”“必须”这类词要多留个心眼——算法和机器学习里很少有绝对成立的说法。比如前面提到的“XGBoost基学习器只能是CART树”出现了“只能”基本就能判断是错的。另一个技巧是“选项对比法”。有一道关于聚类算法的多选题四个选项中有两个描述的是K-Means的缺点一个描述的是DBSCAN的优点另一个是说“K-Means可以自动确定K值”。如果你能判断出“自动确定K值”是错的K-Means需要预先指定K那答案基本就锁定在其余三项了。这种排除法在多选题中非常管用它不需要你100%确定每个选项只需要你能确定一个明显的错误选项。5.4 考后复盘与后续准备建议笔试结束后的三个多小时我做的事情不是对答案而是做“结构化复盘”。我把每道题考察的知识点列了一张清单按照“掌握牢固”“一知半解”“完全不会”三档分类。最后发现“一知半解”的题大多集中在“业务约束转算法模型”这一类——比如带状态的分层图、带权匹配、时间窗约束。这说明我的纯算法基础还不错但把算法灵活应用到业务场景的能力还需要加强。针对这个薄弱点我后续做了两件事一是集中刷了一段时间的“状态压缩图论”类题目熟练了状态维度的扩展技巧二是找了几个本地生活场景外卖调度、物流路径规划、ETA预估自己尝试建模把算法题里的思路迁移到真实业务中。说实话这个复盘比多做几套模拟题对我的帮助大得多因为它真正指出了我的知识盲区在哪。从我个人的体会来说饿了么这批算法岗笔试最大的特点就是业务感强。同样是考Dijkstra它不会直接给你一个图让你求最短路而是会包装成骑手配送场景同样是考KMP它会增加一个容错条件让你思考如何扩展。所以准备的时候建议不要只埋头刷题而是多想一想“这个算法在本地生活业务里能用来做什么”。你越是能把算法和业务联系起来遇到变体题时就越有思路。
返回列表