
2023年飞猪秋招算法岗的笔试我是在一个周六下午做的。全程两个半小时牛客网双机位监控系统里一共三道编程题加二十几道选择题。说实话飞猪这场笔试在当年大厂算法岗里不算最难的但风格非常鲜明偏向业务落地、偏向搜索推荐和旅行场景的工程实现而不是那种纯刷题拼模板的地方。做完之后我花了不少时间复盘把每道题的考点、现场思路和事后优化都整理了一遍。这篇文章就当是给后面准备大厂算法岗笔试的同学一份参考也记录一下我对这类业务型算法笔试的理解。1. 笔试前的判断飞猪算法岗到底在考察什么能力投飞猪算法岗之前我特意翻过它的岗位描述。飞猪的算法团队主要覆盖的方向很明确旅行搜索、个性化推荐、交易转化、价格策略、供应链优化、智能客服。这和字节、腾讯那种以通用推荐和内容分发为主的算法岗相比业务属性明显更重。所以笔试的题目设计基本可以推断出它不是在考察你会不会背某篇论文而是考察你面对真实旅行场景时能不能用算法给出可落地的解法。从实际题目来看我的判断基本被验证了。选择题里数据结构、机器学习基础和深度学习基础都有但占比最高的是业务场景题比如某用户在国庆前一周频繁搜索三亚的酒店如何给他做意图识别这类。编程题则更直接三道题分别是字符串匹配、带约束的路径规划和推荐系统的召回策略设计。没有一道是纯粹的模板题每道题都包裹着一个业务外壳。我的建议是准备这类笔试前一定要先做一件事把岗位描述读三遍。搞清楚这个岗位到底在做什么然后针对性准备。飞猪这种业务型算法岗笔试考察的核心就三个词基础扎实、代码利索、业务理解。基础扎实是指数据结构和机器学习功底代码利索是指能在有限时间内写出能跑的完整代码而不是只写个伪代码业务理解是指能在题目里快速识别出它背后对应的真实问题。另外提醒一下笔试环境是牛客网的ACM模式也就是需要自己处理输入输出。很多同学平时刷LeetCode习惯了核心代码模式到ACM模式下会很不适应。飞猪这场笔试的三道题都是ACM模式第一道题就有人因为输入解析问题卡了半天。平时一定要多在牛客网或者类似平台上练ACM模式这真的是血泪教训。2. 选择题部分的考点分布算法基础、机器学习与手撕细节飞猪笔试的选择题一共二十几道单选多选混在一起多选少选不给分。整体难度中等偏上但真正拉开差距的往往是几个偏门细节题。我回忆了一下大概可以分成四类。2.1 数据结构与算法基础题KMP、排序、堆、哈希全都有选择题里数据结构部分大概占了三分之一。第一个让我印象深刻的是一道KMP算法题给定模式串pabacaba求它的next数组。这个考点本身不冷门但放在飞猪的卷子里说明他们很看重基本功。KMP的next数组计算是经典中的经典但很多人考研之后就没再手推过现场容易卡住。我当时的做法是先把KMP的next数组定义在脑子里过一遍next[i]表示模式串前i个字符组成的子串中最长相等前缀后缀的长度。对于abacaba来说逐个计算是这样的next[0] -1或者0取决于定义next[1]表示a前缀后缀都没有匹配的是0next[2]表示ab前缀a和后缀b不匹配是0next[3]表示aba前缀a和后缀a匹配长度是1next[4]表示abac最长相等前缀后缀长度是0next[5]表示abaca前缀a和后缀a匹配长度是1next[6]表示abacab前缀ab和后缀ab匹配长度是2next[7]表示整个abacaba前缀aba和后缀aba匹配长度是3。所以next数组是[-1, 0, 0, 1, 0, 1, 2, 3]以next[0]-1的写法算。这种题没有捷径就是平时多手推几遍把next数组的含义吃透考试时才能又快又准。排序算法的考察也比较细我记得有一道题是问在待排序序列基本有序的情况下哪种排序算法性能最优。答案是插入排序因为基本有序时插入排序的比较次数接近n而快排在这种情况下降级成O(n^2)。这题本身不难但选项里有个干扰项是冒泡排序很多人会混淆。冒泡排序在基本有序时如果加了优化标志位也可以在接近O(n)完成但标准教材里的冒泡排序没有标志位优化所以严格来说还是插入排序更优。这种细节题的区分度就在于你是不是真的理解算法本质而不是背结论。堆排序和哈希表的题也出现了。堆排序考的是建堆的时间复杂度这个答案是O(n)很多同学写成O(nlogn)就错了。哈希表考的是开放地址法和链地址法的对比以及负载因子对查找效率的影响。这类题没有太多技巧就是要把基本功打牢每个算法的原理、复杂度、适用场景都要了然于胸。2.2 机器学习基础题损失函数、过拟合与模型评估机器学习部分的选择题主要围绕损失函数、过拟合、偏差方差权衡、模型评估方法这几个方向。有一道题问的是对于分类问题交叉熵损失相比均方误差损失的优势是什么答案应该是交叉熵在梯度下降时收敛更快、更容易跳出局部最优、对概率分布更敏感。这里要理解本质原因均方误差配合sigmoid激活函数时梯度中有sigmoid的导数项当输出接近0或1时梯度趋近于0导致学习缓慢而交叉熵损失和softmax/sigmoid结合时梯度形式简洁不存在这种梯度消失问题。还有一道题是关于过拟合的给定一个训练集上准确率非常高、测试集上准确率很低的模型问最可能的问题是什么以及解决方法。这个就太经典了答案就是过拟合解决方法是正则化、数据增强、早停、Dropout。但要注意题目给的是多选可能在选项中混入了增加模型复杂度这种错误项需要仔细辨别。模型评估那边考了ROC曲线和AUC。题目大概是给出两条ROC曲线问哪条对应的模型性能更好。AUC越接近1说明模型性能越好但要注意ROC曲线本身考的是真正例率和假正例率的权衡不是简单的准确率对比。这种题在面试里也常被追问笔试阶段能答对就不错但后面面试官的追问会更深入比如AUC为什么不受样本不平衡的影响这种问题建议提前准备。2.3 深度学习基础题卷积、池化、BN、学习率策略深度学习部分占比不算特别大但考得很细。有一道题是给定输入特征图尺寸、卷积核大小、步长、填充计算输出特征图的尺寸。公式是输出尺寸(输入尺寸-卷积核尺寸2填充)/步长1。这题只要公式记得准就能答对但容易在步长和填充的取值上犯迷糊特别是当(输入-卷积核2填充)不能被步长整除时不同框架的处理方式不一样题目里通常会给定向下取整还是向上取整。还有一道题是问Batch Normalization在训练和推理阶段的行为差异。训练时BN使用当前batch的均值和方差推理时使用训练阶段统计的全局均值和方差。这个知识点本身不冷门但题目选项里可能混淆了训练时也使用全局统计量这种选项如果不清楚BN的设计初衷很容易选错。BN背后的逻辑是为了解决内部协变量偏移问题加速训练收敛它不只是个归一化操作还引入了可学习的缩放和平移参数。学习率策略那边考了cosine annealing和warmup。这其实已经不是基础范畴了如果没做过深度学习实战可能压根不知道这个。我当时在选择题里看到warmup相关的问题就知道飞猪这个岗位对深度学习实战是有要求的不是只背理论就行。warmup的核心思想是在训练早期用一个较小的学习率让模型参数先稳定下来再逐渐增大到设定的学习率目的是避免训练初期因为参数变化剧烈导致震荡。2.4 业务场景题旅行意图识别与推荐策略业务场景题是飞猪笔试的特色。有一道题大致是用户在搜索框输入十一去三亚系统需要判断用户的意图问最合适的技术方案是什么。选项里有基于词典的规则匹配、基于BERT的分类模型、基于关键词统计的方法等。这道题没有绝对标准答案但结合业务场景最优解通常是一个多层级方案先用规则匹配低成本拦截高置信度的query再用深度模型处理长尾query。这类题目考察的是算法工程师的系统设计思维而不是单纯的模型选择。飞猪这种业务型算法岗日常工作中很大一部分精力就是在处理这类模糊的、有噪声的真实用户请求。所以笔试里出现这种题其实是在传递一个信号这个岗位需要的是能解决实际业务问题的人而不是只会调包调参的人。我的建议是做业务场景题时一定要把思路理清楚先说什么方案最简单直接再说当数据量变大、情况变复杂后怎么演进最后说为什么最终选择某个方案。这其实和面试中的系统设计题思路一致。虽然笔试只要选答案但把每个选项背后的技术逻辑想清楚对后面的面试环节非常有帮助。3. 三道编程题逐题拆解从输入输出到核心算法再到边界条件编程题是笔试的重头戏一共三道难度依次递增。我个人感觉第一道是送分题第二道是拉开差距的题第三道是真正筛选高手的题。下面把三道题都拆开来讲。3.1 第一题字符串匹配的变种KMP还是暴力第一道编程题是个字符串匹配的变种题大致意思是给定一个文本串和一个模式串要求输出模式串在文本串中所有出现的位置但模式串中可能包含通配符?表示可以匹配任意一个字符。文本串长度不超过10^5模式串长度不超过1000。看到这个题我第一反应就是KMP但通配符的存在让标准的KMP不能直接套用。思路有两个选择一是把?当成可以匹配任意字符的特殊逻辑在KMP匹配过程中如果模式串对应位置是?就直接当成匹配成功二是直接用暴力匹配因为模式串长度只有1000文本串长度10^5最坏情况是O(n*m)10^8在C里勉强能过但在Java和Python里可能会超时。我当时选择了改造KMP的思路。核心问题是next数组怎么求当模式串里有?时next数组的语义要调整。?可以匹配任意字符所以在求最长相等前缀后缀时如果对应位置是?那也算匹配。举个例子模式串a?c它的next数组计算时a和c不算相等但当遇到?时比如??这种情况前缀?和后缀?是匹配的因为?可以代表同一个字符也可以代表不同字符。这其实给KMP的实现带来了一个坑在比较字符时不仅要判断两个字符是否相等还要判断是否有一个是?。当时我花了不少时间处理这个细节。另外一个容易错的地方是匹配过程中如果模式串和文本串在某个位置不匹配需要根据next数组回退模式串的指针但回退之后需要重新比较的字符是否还涉及?逻辑不能写错。这类改造KMP的题关键在于把所有字符比较都抽象成一个match函数——两个字符相等或者其中一个是?就算匹配。把所有比较逻辑都收敛到这个函数里后面就不容易乱。最后还要考虑多组数据输入。牛客网的ACM模式通常会表示成多行输入或者T组数据这题的输入格式我记得是每组数据两行第一行是文本串第二行是模式串每组数据之间没有明确的分隔符。这个输入解析在牛客网的测试数据里是个常见的坑很多人程序逻辑没问题就是因为多读了空格或者换行导致结果不对。解决方法是读取时先读一行字符串如果字符串为空可能是空行分隔就跳过或者作为下一组数据的开始。这种IO细节平时一定要多练考试时真的很浪费时间。3.2 第二题带约束的路径规划经典变种Dijkstra第二题是一个路径规划题表面上是求最短路但加了业务约束。大致背景是旅行者在景点之间移动有N个景点和M条路线每条路线有通行时间和通行费用两个属性。要求从起点到终点的所有路线中找到通行时间最短且通行费用不超过给定预算K的路线。N不超过10^3M不超过10^5K不超过10^4。这个题的本质是带资源约束的最短路问题典型的解法是扩展状态的Dijkstra。普通Dijkstra维护的是到达某个结点的最短距离这里需要维护的代价是一个二元组(通行费用, 通行时间)优先队列的排序先按费用从小到大再按时间从小到大。每次从队列中弹出状态如果当前费用已经超过K就剪枝否则尝试扩展邻居。由于费用上限K是10^4N是10^3理论上状态总数是N*K10^7在可接受范围内。不过我当时的实现有个更快的优化直接维护dist[node][cost]表示到达node且花费为cost时的最短时间。然后Dijkstra的松弛条件就是dist[node][cost] time_to_neighbor dist[neighbor][cost fee_to_neighbor]。用优先队列按照dist值从小到大弹保证每个状态只被更新一次。这个就是标准的二维最短路套路在算法竞赛里很常见但在算法岗笔试里出现说明飞猪很看重实际工程中的优化能力。这题有另一个容易踩的坑路径规划问题在数据规模较小且K也不大的时候其实也可以用动态规划求解——dp[i][j]表示走到景点i且总费用为j的最短时间转移就是遍历所有以i为起点的边更新邻居。但这里N10^3K10^4边数M10^5用纯粹的松弛法做复杂度是O(K*(NM))10^4*10^510^9会超时。所以二维Dijkstra才是正解关键在于用优先队列保证每个状态只处理一次避免了大量无效松弛。我当时还处理了一个很隐蔽的边界条件如果起点就是终点答案是0但需要先判断费用是否为0否则输出-1。另外如果有多条路线连接两个景点要保留费用最小且时间最短的那条因为输入数据里可能出现重复边。这种边界条件在笔试中占比不大但错了就是0分所以平时刷题一定要养成先想边界再用例的习惯。3.3 第三题推荐系统的召回策略设计远超普通算法的业务题第三题是压轴题也是最有飞猪特色的一道。题目不直接考某个算法而是给了一个真实的业务场景旅行社区的内容流推荐每个用户有浏览行为序列每个内容有属性标签目的地、内容类型、热度等要求设计一个召回策略从海量内容池中为每个用户召回100个候选内容。这个题没有标准答案考察的是系统设计能力和算法知识的综合运用。我在考试时的思路是分三层召回第一层是协同过滤召回利用用户行为序列中相似用户浏览过的内容做召回第二层是向量召回用双塔模型把用户和内容编码成向量通过内积相似度做近邻搜索第三层是规则和热度兜底保证冷启动用户和有明确意图的用户都能覆盖。写完主体思路后我把重点放在了两块。一块是向量召回的候选生成流程离线用双塔模型训练用户和内容的embedding在线用faiss或者hnsw做近邻检索。另一块是面对数据稀疏和冷启动问题的策略用户第一次访问时没有行为序列这时候要降级到基于热度的召回再叠加基于地理位置的召回——比如用户定位在三亚就先召回三亚的攻略和酒店内容。这题其实是在考察算法工程师能不能跳出算法本身思考问题。第三题写完之后我意识到它和前两题的逻辑一脉相承第一题是基本功第二题是优化能力第三题是系统设计能力和业务理解。飞猪这套笔试题的出题逻辑其实非常完整基础扎实的能拿一百分里的六十分有优化能力但业务理解欠缺的能拿七十分会系统设计的才有可能拿高分。4. 笔试复盘那些答题时没想明白、事后才悟出来的点笔试结束后我花了一周时间复盘。复盘的价值比考试本身更大因为只有真正想明白每道题的考点和出题逻辑才能在后面的面试中对答如流。这里把复盘中的几个重点记录下来。4.1 KMP数组的定义细节影响了整道题的走向必须和出题人保持一致KMP那道选择题的争议点在next数组的定义。常见的有两种一种是next[i]表示长度为i的前缀中最长相等前缀后缀的长度其中next[0]-1next[1]0另一种是next[i]表示当前位置之前的真前缀和真后缀的最长匹配长度next[0]0next[1]0。同样一个模式串两种定义算出来的数组完全不同。题目里明确写了next[i]定义为但我当时记不清题目里给的具体定义形式了只能靠记忆中的标准答案去推测。这个细节提醒我考试时如果题目明确了定义一定要严格按照题目的定义来算不要带入自己的标准。这其实也是工程中经常遇到的问题——代码规范和算法定义在不同团队里可能不同沟通时要以对方定义为准。后来面试的时候也确实被问到了KMP的next数组和优化后的nextval数组的区别所以这块一定要理解透彻。4.2 二维Dijkstra的全状态求解与提前终止优化第二题路径规划的二维Dijkstra事后我复盘时发现代码有一个可以优化的地方因为答案是费用不超过K的最短时间所以理论上当从优先队列中第一次弹到终点节点时就可以直接返回当前时间不需要继续搜索了。因为优先队列保证了按时间从小到大弹出状态第一次弹出终点状态就是最优解。我当时没有做这个提前终止完整跑完了所有状态虽然结果没问题但浪费了不少时间。这个优化的本质是Dijkstra算法的贪心性质优先队列中按代价从小到大弹出节点状态首次弹出的终点状态一定是最优的。这个结论需要想清楚为什么成立假设存在一条更优路径P到达终点那么P上必然存在某个状态被优先队列弹出的时间早于当前状态但Dijkstra已经按代价顺序处理了所有状态所以矛盾。这种优化在实际工程中很常见——搜索空间太大时合理利用问题的单调性提前终止能省很多算力。4.3 推荐系统的多路召回与重排之间的衔接这是面试最喜欢追问的点第三题系统设计题虽然我写了三层召回策略但复盘时发现还缺了一环召回和重排之间的衔接。面试官大概率会追问召回100个候选之后精排怎么做我当时没写精排部分但面试中大概率逃不掉。后来我专门补了这块精排可以用LR、GBDT或者深度排序模型输入特征是用户embedding和内容embedding的拼接、交叉特征、实时行为特征。精排模型的训练样本来自用户真实的点击曝光日志用pairwise或者listwise的loss去优化。如果要给出实际的工程链路大概是这样的召回阶段产生100~200个候选粗排阶段用轻量模型比如双塔少量交叉特征把候选缩小到50个精排阶段用完整的深度模型输出CTR预估分数最后再根据业务规则做多样性和新鲜度调节比如同目的地内容不能连续出现、同一作者的内容一屏最多出现两条。这些细节在笔试时不需要写太多但面试前要完整准备。5. 算法岗笔试备战思路飞猪这套题给后来人的几点建议飞猪秋招笔试的整体风格让我对业务型算法岗笔试有了很清晰的认识。如果你打算投飞猪或者其他电商、OTA平台的算法岗笔试准备可以从这几个维度切入。5.1 按题型维度分块备战优先补足短板第一个维度是题型。选择题部分一定要把数据结构、机器学习、深度学习基本功打牢这个没有捷径就是反复刷题加理解原理。编程题部分要练好ACM模式的输入输出同时把常用算法模板全部吃透KMP、Dijkstra、Floyd、并查集、线段树、滑动窗口、背包DP、状态压缩DP这些都要达到条件反射的程度。我在准备后期给自己定了一个小目标常用数据结构和算法不再看模板代码就能默写。默写是检验掌握程度的唯一标准如果你还需要看着模板写考试时一定卡壳。具体操作上我会每天早上随机抽三个算法默写实现比如今天抽堆排序并查集Dijkstra就手写三个完整代码写完再对照标准答案检查。5.2 按业务方向分块备战刷题时必须带着业务视角第二个维度是业务方向。飞猪的笔试题目不是随便出的每道编程题都对应着真实的业务问题字符串匹配对应搜索query处理路径规划对应旅行路线推荐推荐召回对应信息流推荐。所以刷题时不要只满足于AC了要停下来想一想这道题在真实业务中对应什么场景如果数据量扩大100倍现有解法还成立吗这样做的好处是双重的笔试时能更快识别出题人的考察意图面试时也能更流畅地阐述项目经历。比如你刷了KMP可以想一想搜索场景下的字符串匹配问题刷了Dijkstra想一想地图导航场景下的路径规划刷了推荐召回想一想信息流场景下的匹配逻辑。从题目反推业务场景的能力是区分刷题机器和合格算法工程师的重要标志。5.3 时间分配和心态调整最后再聊两个细节笔试过程中的时间分配也很重要。我的策略是先快速扫一遍全部题目选择题控制在35分钟内完成编程题按从易到难的顺序做每一道编程题先想清楚思路再动手写避免一边写一边改导致代码一团糟。两个细节提醒一下。第一个是关于多选选择题的飞猪的多选选择题是少选不给分的所以拿不准的选项千万不要选宁愿少选也不要错选。第二个是关于编程题的环境牛客网的IDE只有基础的代码补全没有调试器所以写代码时一定要仔细逻辑想清楚再写尽量一遍过。另外笔试题目的编译环境通常是C11、Java 8或较新的Python 3如果要修改代码逻辑千万不要在最后几分钟大改很容易改出更多问题。6. 我把这套题看做什么一次对算法工程师的全链路体检飞猪这套笔试题做下来我最深的体会是它不像传统大厂算法岗那样直白地堆LeetCode hard题更像是一次对算法工程师的全链路体检。从基础能力到优化思路从业务理解到工程意识每个环节都在考察你未来做业务算法时是否有足够的肌肉记忆。第一题考的是基本功和代码实现能力。字符串匹配这种题无论做搜索还是做NLP都绕不开而KMP这种经典算法也是区分背过模板和真正理解的分水岭。第二题考的是优化能力。带约束的最短路问题本质上是如何在有限的资源约束下找到最优解这和推荐系统里在算力预算内做最优决策有异曲同工之处。第三题考的是系统设计能力。多路召回策略的设计直接对应算法工程师日常工作的核心环节。如果你准备投飞猪或者其他以业务为导向的算法岗我的建议是不要只刷算法题同时也要系统整理机器学习、深度学习的核心知识点并且尝试用业务语言去描述每个算法解决的问题、适用的场景、实际落地时的注意事项。这套笔试给了我一次很好的自查机会也让我更清楚自己在哪些方面还有差距。希望这篇复盘能对后面准备类似笔试的同学有帮助也祝正在准备秋招的各位都能拿到满意的offer。