ARTICLE DETAIL

资讯详情

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

2023秋招工程算法岗笔试全解析:高频考点与实战避坑指南

2023秋招工程算法岗笔试全解析:高频考点与实战避坑指南 每年秋招一到算法岗位的笔试就成了讨论度最高的话题。尤其是像饿了么这样的互联网公司工程算法岗的笔试不只看你会不会写代码更看你在有限时间内能不能把真实业务问题抽象成算法模型再落成可运行的代码。2023年这一轮秋招身边不少朋友和我一样投了工程算法岗笔试题目涉及的范围比想象中的要宽字符串算法、数据结构、图论、动态规划、机器学习基础甚至信号控制里的PID、卡尔曼滤波都有可能出现。这篇文章不打算给你堆一份标准答案而是把整个笔试的考察逻辑、高频考点、真题背后的做题思路以及我踩过的坑一次性说清楚。如果你是正在准备算法岗笔试的应届生或者想跳槽到外卖、即时零售这类业务导向型算法岗位的工程师这篇文章应该能帮你少走不少弯路。我尽量按考什么-怎么拆-怎么做-怎么复盘的顺序来讲内容偏向实战不整虚的。1. 工程算法岗笔试在考什么和高频考点背后的逻辑1.1 工程算法岗 VS 纯算法研究岗的考察差异很多同学在准备笔试时会犯一个方向性错误把工程算法岗的笔试当成论文复现或者数学推导考试。实际上工程算法岗和纯算法岗比如搜索算法研究员、NLP算法研究员的考察逻辑有明显差别。纯算法研究岗更看重对 SOTA 模型、论文细节、数学原理的掌握工程算法岗则更看重工程落地能力包括编码基本功、复杂度分析、边界条件处理、业务场景抽象。换句话说工程算法岗的笔试题通常不会让你手推一个复杂的Transformer公式而是更可能给你一个骑手配送路径选择外卖订单队列排序推荐列表重排之类的场景让你用合适的算法去解。我在2023年秋招参加饿了么工程算法岗笔试的时候整体感觉是题目难度不是竞赛级但覆盖面相当广。你很难通过只刷某一种题型蒙混过关必须把基础算法知识体系搭扎实。高频考点主要集中在字符串匹配、排序搜索、数据结构设计、图论、动态规划、贪心以及部分机器学习/智能优化算法。这些算法并不是孤立出现的很多题目都会结合业务场景出题比如用KMP做关键词匹配、用堆做TopK排序、用Dijkstra做路线规划。1.2 从高频考点看工程算法岗的隐性要求我们可以把笔试中出现频率较高的算法考点分一下类。下面这张表是我根据自己的笔试经验以及身边同学在多个平台刷题时总结的考点分布不一定代表官方考纲但作为复习参考非常有用。考点类别代表算法/题目工程场景映射字符串算法KMP、字符串哈希、Manacher搜索词匹配、敏感词过滤排序算法快排、堆排、归并、冒泡榜单排序、TopK、合并有序文件数据结构LRU、跳表、B树、哈希表缓存设计、索引设计搜索算法二分、DFS、BFS、剪枝商品搜索、状态空间搜索图论Dijkstra、Kahn拓扑排序、二分图匹配路径规划、依赖调度、骑手匹配动态规划背包、区间DP、状态机DP资源分配、成本优化智能优化粒子群、模拟退火、遗传算法配送路径优化、参数调优机器学习基础KNN、K-Means、XGBoost、评价指标推荐排序、画像聚类信号控制类PID、卡尔曼滤波运力控制、轨迹预测、设备控制这个考点分布背后其实反映出工程算法岗的一个隐性要求你必须有把业务问题翻译成算法问题的能力。单纯会背算法模板不够你得知道在什么场景下选什么算法以及为什么这个算法适合这个场景。笔试中即使不直接考业务分析也会通过题目描述隐性地引导你往某个算法方向思考。2. 动手算一遍高频字符串算法从KMP的next数组开始2.1 字符串匹配为什么一定是高频考点字符串匹配是工程算法笔试里的钉子户。原因很简单外卖平台每天要处理海量的文本数据包括商家名称匹配、用户评论关键词提取、商品名称标准化、敏感词过滤这些场景本质上都是字符串匹配。KMP 作为最基础的线性时间字符串匹配算法自然成为笔试的首选考察对象。我在笔试前专门把KMP的next数组计算过程手推了好几遍因为这块太容易出错了。网上关于next数组的讲解版本很多有的下标从0开始有的从1开始有的把next定义为失配时跳转的位置有的定义为最长相等前后缀长度。如果不统一口径考试时很容易把自己绕晕。2.2 用abacaba完整推出next数组这里我用一个热词场景中出现的典型例子来说明。假设模式串 p abacaba长度为7。我们要求它的 next 数组。为了统一这里约定 next[i] 表示子串 p[0..i] 的最长相等真前后缀长度注意不包含子串自身。这是LeetCode和很多竞赛代码中采用的前缀函数定义。我们逐个位置计算i0子串为 a真前后缀没有next[0]0。i1子串为 ab前缀集合是 {a}后缀集合是 {b}无交集next[1]0。i2子串为 aba前缀集合是 {a,ab}后缀集合是 {ba,a}交集为 {a}最长长度为1next[2]1。i3子串为 abac前缀和后缀集合相交为空next[3]0。i4子串为 abaca前缀集合和后缀集合交集为 {a}next[4]1。i5子串为 abacab看前缀 ab 和后缀 ab 相等长度为2但长度为3时前缀 aba 和后缀 cab 不相等所以 next[5]2。i6子串为 abacaba前缀 aba 和后缀 aba 相等长度为3长度为4时前缀 abac 和后缀 caba 不相等所以 next[6]3。所以最终 next 数组为 [0, 0, 1, 0, 1, 2, 3]。注意我在第5位计算出的值是2不是0。这一点容易出错我当时第一次手算时就是在这里翻车的。如果题目里的 next[i] 定义为失配时模式串指针跳转的下一位置那往往是在上述前缀函数的基础上做一次右移或者整体加1、减1。不同教材定义不同笔试答题时最好在代码注释里写清楚自己的定义避免因定义歧义被扣分。2.3 KMP匹配过程的关键失配跳转计算完 next 数组我们再看匹配过程。假设文本串 s 为 abacababcabacaba要在其中查找模式串 p。匹配过程大致是文本串指针 i 和模式串指针 j 同步前进当 s[i] 等于 p[j] 时i 和 j 都加1当失配且 j 0 时j 跳到 next[j-1]而 i 不动。这个跳转避免了对文本串的回溯从而保证整体时间复杂度 O(nm)。在笔试中KMP 通常不会只让你写出匹配结果而是会让你补全 next 数组或者处理改进版 KMPnextval的计算。我建议你至少掌握两种写法一种是前缀函数版本一种是考研/教材常见版本的 next 数组计算。考场上要根据题目描述灵活切换。我自己的经验是考前把KMP模板背熟到能盲写同时把 nextval 的计算也练一遍。因为很多题目会在 KMP 基础上做变形比如统计模式串在文本中出现的次数、求最小循环节。最小循环节的问题直接基于 next 数组解决循环节长度 L n - next[n-1]前缀函数版如果 n % L 0则 L 就是最小循环节长度。这个点也经常在笔试里以小问形式出现。3. 排序、图论和动态规划基础题型里最容易埋的坑3.1 排序算法会写和能说清复杂度是两回事排序算法是笔试的开胃菜但也是最容易暴露基本功不扎实的地方。很多人能默写快排但被问到快排最坏情况下的复杂度是多少为什么就卡住了。2023年秋招笔试里我就遇到了要求手写堆排序构造过程的题目不仅要写出结果还要说明建堆和调整的过程。先看几个高频排序算法的复杂度对比排序算法平均时间复杂度最坏时间复杂度空间复杂度稳定性冒泡排序O(n^2)O(n^2)O(1)稳定快速排序O(n log n)O(n^2)O(log n)不稳定堆排序O(n log n)O(n log n)O(1)不稳定归并排序O(n log n)O(n log n)O(n)稳定冒泡排序在业务里用得少但笔试中偶尔会作为基础题出现。尤其是它的优化版记录本轮是否发生过交换如果没有提前结束也值得掌握。下面这个 C 实现我建议背下来void bubbleSort(vectorint arr) { int n arr.size(); for (int i 0; i n - 1; i) { bool swapped false; for (int j 0; j n - 1 - i; j) { if (arr[j] arr[j 1]) { swap(arr[j], arr[j 1]); swapped true; } } if (!swapped) break; } }核心考察点不只是能不能写出来而是你知不知道什么时候用冒泡不合适。比如 n10万 时O(n^2) 的算法一定会超时这时候就得上快排或归并。笔试中必须在代码里体现出我会分析复杂度这个意识。堆排序的考察频率也很高。它的核心操作是上浮和下沉建堆的过程是从最后一个非叶子节点开始向下调整。有些题目会结合海量数据 TopK 来考在一堆数里找最大的 K 个用大小为 K 的小顶堆堆顶就是当前第 K 大的数。这个思路在订单榜单、商品热门排序里都可以用非常工程化。归并排序则经常结合求逆序对数量来考。求逆序对的核心就是在归并过程中统计左半部分比右半部分大的次数。这个问题在推荐系统里评估排序相关性时也有类似思想笔试中如果遇到直接套归并排序模板即可。3.2 图论Dijkstra、Kahn拓扑排序和二分图匹配图论是工程算法岗笔试的重头戏。外卖平台的场景里有大量图论问题骑手从商家到用户家的最短路径、多仓库配货的调度、任务依赖关系管理都可以抽象成图结构。Dijkstra算法是最短路径问题的基础堆优化版本必须熟练掌握。笔试中常见的变体是给一个带权无向图求某个节点到其他所有节点的最短路径或者是加了某些节点不可走的限制条件。模板不复杂核心在于理解为什么需要优先队列以及为什么要用 visited 数组标记已确定最短路径的节点。Kahn算法用于拓扑排序是处理依赖关系的利器。假设有 n 个任务每个任务有前置任务求一个合法的执行顺序。Kahn算法的思路很直观每次从图中取出一个入度为0的节点然后删除它的出边循环直到所有节点都被取出。如果最后还有节点未被取出说明图中有环那么这个任务依赖关系无解。这个点经常以课程表I/II的形式出现。二分图匹配也是热词中提到的高频考点尤其是 HK 算法Hopcroft-Karp 算法。很多人听到二分图匹配就害怕实际上工程算法岗笔试中更多考的是匈牙利算法的思想HK 算法考到顶多让你分析它的复杂度优势。二分图匹配的业务场景很典型比如把一组骑手匹配到一组订单上一个骑手同时只能接一单目标是让匹配对数最大化。这个模型就是标准的二分图最大匹配。即使实现不了 HK至少要把匈牙利算法的 DFS 增广思路写清楚。我个人在笔试中遇到的图论题往往是结合场景出的小题。比如给定城市道路图求从 A 到 B 的最短距离就是 Dijkstra给定多个配送点求访问所有点后回到起点的最短路径这就变成了 TSP 问题属于 NP-Hard不能用简单 Dijkstra 解决。如果你能判断出题目类型并说明这个问题是 NP-Hard所以采用贪心或近似算法就会比闷头写代码得分高。3.3 动态规划和贪心状态定义是最难的动态规划在笔试中的出现概率几乎是100%。但工程算法岗不会考太偏的竞赛 DP重点往往集中在背包问题、最长上升子序列、最大子数组和、编辑距离、状态机DP这几个模型里。做题的时候我的体会是状态定义是重中之重。没有想清楚状态定义就开写代码基本会越写越乱。举个例子最长上升子序列问题状态 dp[i] 表示以第 i 个元素结尾的最长上升子序列长度。转移时遍历所有 j i如果 nums[j] nums[i] 就更新 dp[i] max(dp[i], dp[j]1)。这个状态定义和转移方程都很自然。但如果你把 dp[i] 定义成前 i 个元素的最长上升子序列长度转移就很容易出错因为新元素可能并不增长子序列但前缀的最优解仍然要从前面继承。贪心算法在笔试中往往以想不到的形式出现。比如最大区间调度给定一堆区间选尽可能多的互不重叠的区间按结束时间排序后依次选择即可。贪心算法的难点在于证明贪心策略的正确性笔试中如果时间紧张至少要能举几个反例验证一下贪心策略是否合理。我见过不少同学栽在直觉上贪心正确实际是错的这种情况里。4. 笔试题里的机器学习/智能优化算法其实考的是概念和场景对应4.1 粒子群PSO和模拟退火优化类算法怎么考热词里多次出现粒子群算法原理模拟退火算法这并非偶然。在外卖配送、路径规划、库存优化这类问题里很多组合优化问题没有精确多项式解法工程上常用启发式算法。笔试中考察粒子群或模拟退火通常不会让你实现完整代码而是考察你对算法核心思想的描述以及参数含义的理解。粒子群算法的核心是模拟鸟群觅食行为。每个粒子代表一个候选解有位置和速度两个属性。迭代过程中粒子根据个体最优 pbest 和全局最优 gbest 来更新速度和位置。更新公式为v w * v c1 * r1 * (pbest - x) c2 * r2 * (gbest - x) x x v其中 w 是惯性权重控制全局搜索和局部开发能力c1 和 c2 是学习因子分别控制飞向个体最优和全局最优的趋势r1 和 r2 是 [0,1] 之间的随机数。笔试如果问你为什么 w 大时全局搜索强你要能回答惯性权重越大粒子保持原速度的趋势越强不容易被局部最优吸引所以更有利于跳出局部最优。模拟退火的思路来自冶金学中的退火过程。核心是温度参数 T 和 Metropolis 准则在温度高时以一定概率接受较差的解随着温度降低接受较差解的概率越来越小。这样做的目的是在搜索初期充分探索解空间避免一上来就陷入局部最优。笔试中常问的点是为什么模拟退火能跳出局部最优答案就是它以概率接受劣化解条件概率与温度和能量差有关。这类题目考的不是代码而是你真正理解算法的思想。我的建议是复习时把每个算法用一两句话概括再准备一个实际应用场景。比如粒子群可以用于广告出价策略的参数寻优模拟退火可以用于骑手配送路线优化。4.2 机器学习基础KNN、K-Means、XGBoost等机器学习基础也是工程算法岗笔试的常见内容但考察深度通常止步于概念理解。热词中出现的 KNN 应用能力、聚类算法、XGBoost 都是典型的考点。KNNK近邻的核心是物以类聚新样本的类别由它最近的 K 个样本投票决定。笔试常问的有三点K 值的选择对结果的影响、距离度量的选择欧氏距离、曼哈顿距离、以及计算复杂度问题。对于工程算法岗你还要知道KNN是惰性学习训练阶段没有显式模型预测阶段才计算距离所以大数据量下预测效率低。K-Means 是无监督聚类算法流程是选择 K 个初始质心迭代交替进行分配样本到最近的质心和重新计算质心直到收敛。笔试中的常见考点是初始质心选择的影响、肘部法则确定 K 值、K-Means 的局限性对异常点敏感、适合凸形簇。XGBoost 在热词里也出现了它是工业界非常常用的梯度提升树模型。笔试中一般考它的核心思想和与传统 GBDT 的区别。XGBoost 的改进主要在损失函数加入了二阶泰勒展开利用了一阶导和二阶导、加入了正则化项防止过拟合、支持列采样、以及基于预排序的近似直方图算法加速。如果面试官现场问XGBoost 为什么比 GBDT 快你要能提到它在特征分裂时做了并行化处理和近似分位数草图。4.3 PID算法和卡尔曼滤波工程控制方向也要懂一点热词里出现的 PID 算法、卡尔曼滤波算法让很多投递算法岗的同学措手不及。这类题目通常出现在偏工程实现或偏硬件/控制方向的岗位笔试题中饿了么这类平台有时也会涉及智能硬件、机器人配送等方向所以出现 PID 并不奇怪。PID 控制器是一个经典反馈控制算法。P 代表比例项作用于当前误差I 代表积分项累积历史误差消除稳态误差D 代表微分项预测误差变化趋势抑制超调。笔试常考的是位置式 PID 和增量式 PID 的区别。增量式 PID 的输出是控制量的增量公式为Δu Kp * (e(k) - e(k-1)) Ki * e(k) Kd * (e(k) - 2e(k-1) e(k-2))增量式 PID 的好处是输出的是增量不会因积分累积导致大范围饱和即使执行机构故障也不会让控制量突变。卡尔曼滤波则是用于状态估计的算法核心是预测和更新两个步骤。笔试中如果出现卡尔曼滤波一般只要求说出它的应用场景比如轨迹预测、传感器融合和基本思想在噪声存在的情况下用预测值和观测值加权估计出最优状态权重由协方差矩阵决定。不需要把五条公式全部背下来但至少要能画出预测-更新循环的流程。5. 工程算法岗的压轴题手写LRU和场景设计题5.1 LRU缓存数据结构设计题的经典代表LRULeast Recently Used最近最少使用是工程算法岗笔试中出现频率相当高的设计题。它考察的不是某个复杂算法而是你对基础数据结构的组合运用能力在 O(1) 时间内完成 get 和 put 操作。LRU 的经典实现是哈希表 双向链表。哈希表负责 O(1) 查找节点位置双向链表负责维护访问顺序。每次 get 时把对应节点移到链表头部每次 put 时如果 key 不存在插入新节点到头部如果容量超限删除链表尾部节点如果 key 已存在更新值并移到头部。一个简化版的 C 实现思路如下细节略class LRUCache { private: int cap; listpairint, int cache; unordered_mapint, listpairint, int::iterator mp; public: LRUCache(int capacity) : cap(capacity) {} int get(int key) { if (mp.find(key) mp.end()) return -1; auto it mp[key]; cache.splice(cache.begin(), cache, it); return it-second; } void put(int key, int value) { if (mp.find(key) ! mp.end()) { auto it mp[key]; it-second value; cache.splice(cache.begin(), cache, it); return; } if (cache.size() cap) { auto last cache.back(); mp.erase(last.first); cache.pop_back(); } cache.emplace_front(key, value); mp[key] cache.begin(); } };写这道题的时候最容易犯的错误是忘了 erase 哈希表中的过期节点或者忘记 splice 之后迭代器仍然有效。如果你在笔试中能一次性跑通这道题的得分基本就稳了。5.2 外卖业务场景题路径规划、运力调度、排序重排除了经典数据结构题工程算法岗笔试还会出现与业务强相关的场景设计题。这里我结合自己的经验和热词中反复出现的配送路径排序来展开。一类典型题目是配送路径优化。比如在有多个订单需要配送的情况下如何安排骑手的配送顺序使总距离最短。这个问题本质是 TSP 或车辆路径问题VRP是 NP-Hard 的。笔试不会让你在有限时间内求出精确解而是更看重你的建模范式和求解思路。我的答题套路是先明确输入输出和约束条件然后抽象成 TSP/VRP 模型说明精确解法比如动态规划求解小规模 TSP在大规模场景下不可行最后给出启发式解法比如最近邻算法生成初始解再用模拟退火或 2-opt 局部搜索优化。这样答既展示了对问题本质的理解又体现了工程落地的思路。另一类场景题是重排序问题。比如在搜索结果页需要对候选商品进行排序给定点击率、转化率、好评率等多个信号如何设计打分函数。这其实是在考你对线性加权排序、以及机器学习排序Learning to Rank模型的基本理解。笔试中可能只需要写一个简单的 score w1 * ctr w2 * cov w3 * rating 公式并解释权重如何学习。如果能提到先离线学权重、再上线做 A/B 测试就更有工程味道。5.3 面对没见过的场景题怎么稳住不慌我在秋招笔试里遇到过一道题题目给了很长时间的上下文描述了一番如何在恶劣天气下做运力调度然后问算法思路。我第一反应不是马上写代码而是先提取关键信息目标是什么、约束是什么、数据规模多大、允许的复杂度是多少。这类题目显然没有一个标准答案。我的处理方法是分三步走第一复述问题向自己确认理解是否正确笔试中可以在草稿或注释里写出来第二提出一个 basline 解法哪怕是最简单的贪心也要先保证有解第三在这个基础上谈优化空间比如加入时间窗、考虑骑手实时位置等约束。这样做即使拿不到满分也至少能让阅卷人看到逻辑完整的分析过程。6. 备考时间线和个人踩坑复盘6.1 从真题出发三轮复习法如果你距离笔试还有一段时间我比较推荐三轮复习法。第一轮约2-3周打基础。把常见数据结构和算法全部过一遍包括数组、链表、栈、队列、哈希表、二叉树、堆、图、排序、搜索、动态规划、贪心。重点是知道每个算法的适用场景和时间复杂度。这个阶段不要追求刷题数量而是追求每类题型至少能做出来 5-10 道。第二轮约2周刷真题和模拟题。在牛客网、LeetCode、洛谷等平台找往年大厂算法岗笔试真题掐时间模拟。这个阶段要训练的是做题节奏先做有把握的题再做难题不要在一道题上耗太多时间。第三轮约1周冲刺整理。把高频考点的手写模板整理到一页纸里包括二分模板、快排模板、并查集、KMP、Dijkstra 等。每天默写一遍确保考场上不需要现场想。6.2 我在笔试中最容易踩的坑分享几个我自己亲身体会过的坑希望你能避开。第一个坑是边界条件处理。很多题目不是算法不会做而是数组越界、空输入、单元素输入这些边界情况没有考虑。比如最长上升子序列数组长度为 1 时直接返回 1KMP 匹配时模式串长度大于文本串长度直接返回空。建议每题写完代码后先用最简单的输入跑一遍逻辑再提交。第二个坑是不注意数据范围导致溢出或超时。题目如果给的数据范围是 10^5 级别O(n^2) 几乎肯定超时如果涉及乘法要用 long long 而不是 int。笔试中的时间限制往往比本地环境更严格有时候你本地跑通了提交却提示超时就是因为复杂度分析没做好。第三个坑是输入输出格式。有些在线笔试平台让你自己处理输入有的会给你一个方法签名让你实现。2023年秋招饿了么笔试用的是牛客系统部分题目自带输入输出模板但有些需要自己写。我见过有人算法正确却因为没读入多组测试数据而0分这种情况实在太可惜。第四个坑是代码模板不熟。比如手写快排时 partition 函数写错或者写 Dijkstra 时忘了 heap 里要存 pair 并按照 first 排序导致逻辑全错。解决方案就是考前把模板背到肌肉记忆的程度考场上留出脑力去处理题目本身的特殊性。6.3 笔试结束后的复盘方法笔试结束不代表万事大吉。我的习惯是趁记忆清晰立刻把每道题的题意和我的解法简单记录到笔记里。然后把没做出来的题在当天或者第二天重新做一遍并总结知识盲区。复盘时重点关注三类问题第一类是完全没思路的题说明对应知识模块有漏洞需要补基础第二类是思路对但代码没写出来的题说明编码熟练度不够需要多练模板第三类是写完但超时/超内存的题说明复杂度分析和数据结构选型需要加强。通过这样的复盘你不仅能为下一次笔试做准备还能在后续面试中把笔试题目作为项目经验的一部分来讲述展示你的问题分析和解决能力。最后再分享一个小技巧笔试前不用再把所有算法从头看一遍重点看自己最容易出错的部分。我在每次笔试前都会用15分钟默写一遍 KMP 的 next 数组、快排、Dijkstra、LRU 的代码这几样熟了之后整场考试的信心会稳很多。算法这条路没有捷径但多复盘一次下一次遇到同样题型就能少踩一个坑。
返回列表