ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

爱奇艺算法岗笔试复盘:KMP、机器学习与深度学习考点详解

爱奇艺算法岗笔试复盘:KMP、机器学习与深度学习考点详解 爱奇艺2020校招算法岗笔试第二场虽然过去有一阵子了但这套卷子在我带过的几届学弟学妹中反复被提起原因很简单它不像某些厂笔试那样专抠冷门算法题而是把数据结构、机器学习基础、深度学习考点和视频业务场景全都揉在了一起覆盖面广、梯度分明非常适合拿来当算法岗校招笔试的“体检表”。这篇文章我就按“现场复盘”的方式来写把第二场里出现频次高、丢分多的考点逐个掰开讲一遍。不论你是正在准备秋招、还是工作几年想回来补基础照着这套思路过一遍都会比盲目刷题更高效。我会把每道题的解题逻辑、容易踩的坑、以及同类题的复习方向都讲到尽可能还原我当时做题的真实思路。1. 试卷整体结构与考察逻辑1.1 题型分布与时间安排先说整体感受。这套题满分100分考试时间大概90到120分钟题型分三块选择题、填空题/简答题、编程题。选择题占大头覆盖机器学习、深度学习、数据结构、概率论和线性代数编程题一般两道一道偏经典算法一道偏业务场景模拟。我印象里比较清晰的题量安排如下题型题量建议用时考察重点单选题15题左右25分钟机器学习基础、深度学习、概率统计多选题5题左右10分钟易混淆概念、工程经验填空题/简答3题左右15分钟算法原理推导、模型结构理解编程题2题40分钟数据结构、动态规划、贪心算法考试时间看起来宽裕实际上很紧张。尤其是编程题很多人不是不会做而是前面选择题纠结太久导致后面代码没时间调完。我的建议是选择题每道不超过1分半拿不准的先标记不要恋战后面检查时再回头想。1.2 考察侧重点与命题风格爱奇艺的算法笔试第二场有个显著特点不追求偏怪难而是考察“基本概念是否真懂”和“代码能否一遍写对”。同样是考KMP它不会直接让你背next数组而是给一个具体模式串让你算next数组同样是考动态规划它会用视频推荐、字幕匹配这种业务场景来包装但内核还是经典模型。从考点分布来看机器学习占比最高大概40%左右数据结构与算法占30%深度学习和业务场景题占30%。这和爱奇艺以视频为核心、算法大量用于推荐、搜索、审核的业务形态有很大关系。另外提醒一下很多题表面是选择题实际上要求你动笔算。比如给你一个样本集让算信息增益给你一个SVM的间隔表达式让判断哪个点是支持向量。这类题没法靠“感觉”蒙必须对公式和计算过程熟。2. 数据结构与算法真题解析2.1 字符串与KMP算法next数组的计算第二场笔试题里有一道很经典的KMP题原题大意是对于模式串pabacaba求其next数组。这里有个大坑不同教材对next数组的定义不完全一样有的是“最长相同前后缀长度”有的是“失配时模式串跳转的位置”。如果你不先确认题目定义直接套自己背的模板很容易整道题全错。我按最常见的一种定义来算next[i]表示当模式串第i个字符从0开始失配时模式串指针应该回退到的位置其中next[0] -1而next[i] 前缀函数prefix[i-1]。先求pabacaba的prefix数组prefix[i]表示p[0..i]的最长相等真前后缀长度p[0] aprefix[0] 0p[0..1] ab没有相等前后缀prefix[1] 0p[0..2] aba最长相等前后缀是aprefix[2] 1p[0..3] abac没有prefix[3] 0p[0..4] abaca最长是aprefix[4] 1p[0..5] abacab最长是abprefix[5] 2p[0..6] abacaba最长是abaprefix[6] 3所以prefix数组为[0, 0, 1, 0, 1, 2, 3]。按next[0]-1, next[i]prefix[i-1]换算得到next [-1, 0, 0, 1, 0, 1, 2]这里要注意如果题目使用另一种定义直接把prefix数组当作next数组结果就成了[0, 0, 1, 0, 1, 2, 3]。两种版本在牛客、力扣、王道等资料里都能见到所以考试时先花10秒钟看题目给的是哪种定义比闷头算更稳。KMP的代码实现也要能默写尤其是求next数组的递推过程。我用Java写了一个版本思路是“双指针回溯”public int[] getNext(String p) { int n p.length(); int[] next new int[n]; next[0] -1; int i 0, j -1; while (i n - 1) { if (j -1 || p.charAt(i) p.charAt(j)) { i; j; next[i] j; } else { j next[j]; } } return next; }这段代码里最容易被忽视的是else分支的回退逻辑当字符不匹配时j要跳转到next[j]而不是简单的j--。很多人在笔试时就是因为这里写错导致KMP退化成O(n*m)。2.2 排序与分治思想的变体考察排序算法在校招笔试里从不会缺席但爱奇艺第二场并没有直接让你手写快排而是考察排序思想的变体。有一道印象很深的题给一个未排序数组要求找出第K大的数时间复杂度越优越好。本质上这就是快速选择算法Quick Select核心思路借鉴快速排序的partition操作每次选一个基准元素把数组分成小于基准和大于基准两部分然后判断第K大落在哪一侧只递归那一侧。Python实现如下import random def findKthLargest(nums, k): def partition(left, right): pivot_idx random.randint(left, right) pivot nums[pivot_idx] nums[pivot_idx], nums[right] nums[right], nums[pivot_idx] store left for i in range(left, right): if nums[i] pivot: nums[i], nums[store] nums[store], nums[i] store 1 nums[right], nums[store] nums[store], nums[right] return store left, right 0, len(nums) - 1 while True: pos partition(left, right) if pos k - 1: return nums[pos] elif pos k - 1: left pos 1 else: right pos - 1时间复杂度平均O(n)最坏O(n^2)。通过随机选择基准元素来避免最坏情况是面试中需要主动说出来的优化点。如果你只回答“先排序再取第K个”虽然答案对但复杂度O(n log n)不是最优在笔试中只能拿一半分。类似的变体还有求数组前K个高频元素、求中位数、求最小的K个数。复习时可以把它们归为一类——凡是和“第K个/前K个”有关的问题优先想堆排序和快速选择前者适合海量数据、后者适合数组可改的场景。2.3 动态规划与贪心策略的选择题剖析编程题里有一道典型的区间调度变体背景改成了“视频上传任务调度”给定N个任务的开始时间和结束时间每个任务完成后可以释放审核资源问一天内最多能完成多少个任务。这个场景本质就是经典贪心问题——按结束时间排序每次选择结束最早且不与当前时间冲突的任务。证明思路也要掌握如果存在一个最优解它的第一个任务不是结束时间最早的那个那么用结束时间最早的任务替换它不会与其他任务冲突所以贪心选择安全。这类“贪心选择性最优子结构”的证明套路在简答题里经常考。另一道编程题是动态规划的包装题题干大概是“计算两个视频标题文本的相似度”实际要求是求最长公共子序列长度。状态转移方程如下dp[i][j] dp[i-1][j-1] 1, 当 s1[i-1] s2[j-1] dp[i][j] max(dp[i-1][j], dp[i][j-1]), 当不相等注意边界条件是dp[0][j]和dp[i][0]都等于0因为空字符串和任意字符串的公共子序列长度为0。如果题目要求输出具体子序列还需要额外开一个direction数组记录每个状态是从哪里转移来的考试时建议先写长度版本如果时间充裕再扩展回溯逻辑。3. 机器学习与深度学习基础题3.1 基础概念题这些分必须拿稳爱奇艺第二场笔试题给人的感觉是机器学习基础概念考得非常细几乎没有送分题。我整理了几道典型题目和对应的复习要点你们可以直接对照自查。有一道多选题问“下列哪些方法可以缓解过拟合”选项包括L1正则化、L2正则化、Dropout、数据增强、增大模型参数量。正确答案是前四个。很多人会把L1和L2搞混其实两者都能抑制过拟合L1还会带来稀疏性适合做特征选择。增大模型参数量会加重过拟合属于反向操作。这类题没有技巧只能靠平时积累。另一道题关于Batch Normalization问“以下关于BN的说法错误的是”。BN的核心作用是缓解内部协变量偏移让每一层输入分布稳定从而可以使用更大的学习率、加快收敛。但要注意BN在训练时使用当前batch的均值和方差在推理时使用训练阶段累积的全局统计量很多人在这里丢分是因为混淆了训练和推理两个阶段的行为。还有一道题考察SVM中核函数的作用把低维空间线性不可分的数据映射到高维空间使其线性可分。许多人的误区是“核函数降低了计算复杂度”严格来说核技巧避免的是“在高维空间中显式计算内积”而不是“降低映射本身的复杂度”。这个表述差异在选择题里就是送命题。3.2 模型训练中的常见问题这一节我认为是整套卷子里最“拉分”的部分因为单纯背书的人在这里会暴露。比如考过一个问题“训练深度神经网络时梯度消失的根本原因是什么”答案是链式法则连乘导致梯度逐层衰减尤其是在使用Sigmoid激活函数时导数最大只有0.25多层累乘后梯度迅速趋近于0。引申出来的考点是激活函数的选择。ReLU之所以被广泛使用是因为它在正半轴的导数为1可以缓解梯度消失但ReLU也有“神经元死亡”问题即输入为负时梯度恒为0一旦某个神经元落入这个区间就很难再恢复。Leaky ReLU和ELU就是针对这个问题提出的改进笔试中常考它们之间的差异。关于集成学习爱奇艺第二场考过Bagging和Boosting的对比。我用一张表来总结方便你们记忆维度BaggingBoosting样本采样有放回采样各模型独立每轮调整样本权重模型训练可并行串行目标降低方差降低偏差代表算法随机森林GBDT、XGBoost、AdaBoost对异常值敏感度相对不敏感较敏感我当年做这类题的经验是不要死记“谁降低方差谁降低偏差”而是从机制上理解。Bagging通过多个模型投票/平均来平滑掉个别模型的波动所以降方差Boosting每一轮都在拟合前一轮的残差逐步逼近真实值所以降偏差。这里补充一个容易被考到的细节随机森林的随机性来自两个维度一个是样本的随机采样一个是特征的随机子集。如果题目问“随机森林中每棵树训练时使用了多少样本”答案是大约63.2%的原始样本因为有放回采样中约有36.8%的样本从未被抽中这些样本叫袋外数据OOB可以直接用来做无偏验证。这个考点在选择题里出现率很高很多人不知道。3.3 深度学习经典考点感受野与Attention机制深度学习部分爱奇艺第二场考得比较克制但每一题都很有代表性。有一道题问堆叠3个3×3卷积步长为1padding为1其感受野相当于一个多大的卷积答案是7×7。推导过程是第一个3×3卷积后每个输出像素对应输入3×3区域第二个3×3卷积后对应输入5×5区域第三个后对应7×7区域。这也是为什么VGG等网络喜欢用多个小卷积核替代大卷积核参数更少、感受野相同、非线性表达能力更强。Attention机制相关的题也出现过比如“为什么Transformer中的Self-Attention能缓解长距离依赖问题”。传统RNN处理长序列时信息需要经过多个时间步逐步传递容易丢失或衰减而Self-Attention直接计算序列中任意两个位置之间的依赖权重一步到位所以能更好地捕捉长距离关系。关键要理解Query、Key、Value三个向量的作用Query关注目标位置要“找什么”Key是当前位置“能提供什么”Value是“实际提供的内容”注意力权重就是Query和Key的相似度经过Softmax后的结果。Word2Vec也考过主要区分CBOW和Skip-gram。CBOW用上下文预测中心词适合小数据集Skip-gram用中心词预测上下文对低频词效果更好。这个点是自然语言处理的基础算法岗笔试出现率很高。4. 业务场景与工程实现题4.1 推荐场景从召回到排序的完整链路爱奇艺的业务核心是视频所以笔试中必然出现推荐相关题目。有一道简答题问的是“请简述推荐系统的召回和排序阶段各自的作用及常用方法”。这道题看似开放实则有固定得分点。召回阶段的目标是从海量视频库中快速筛选出几百个候选要求速度快、覆盖率广。常用方法包括基于物品的协同过滤ItemCF、基于用户的协同过滤UserCF、双塔模型向量召回、Item2Vec等。这里有个容易混淆的点协同过滤和向量召回的本质区别在于前者是显式地利用“物品共现”或“用户行为相似度”来计算后者是把用户和物品分别映射到低维向量空间用内积或余弦相似度做近似最近邻检索。排序阶段的目标是对候选进行精细打分常用模型从LR、FM到GBDT、DeepFM、DIN不等。笔试中如果问“排序模型为什么用GBDT而不是LR”得分点是GBDT能自动学习特征组合、对非线性关系拟合更强缺点是树模型不擅长处理高维稀疏特征所以业界常把LR和GBDT结合起来用GBDT做特征工程再把结果输入LR或DNN。如果题目进一步追问“如何评估推荐效果”除了离线常用的AUC、GAUC、Hit RateK之外还要提线上AB实验。这是校招笔试的加分项说明你不只会跑模型还懂业务闭环。4.2 视频业务中的算法落地画质评估与内容理解爱奇艺第二场还有一道场景题让我印象很深大致是如何在不依赖原始参考视频的情况下自动评估用户上传视频的画质这就是典型的无参考图像/视频质量评估问题。传统的全参考指标如PSNR、SSIM需要原始视频做对比但用户上传的视频往往没有原始版本所以必须用无参考评估方法。工程上常见的思路有两类一是提取视频的失真特征比如模糊度、块效应、噪声水平再训练回归模型预测主观评分二是用深度神经网络直接端到端学习质量映射输入视频帧输出质量分数。这题在实际业务中很有价值因为视频平台每天有大量UGC内容上传如果画质过差会直接影响用户体验。笔试中只要你能说出“全参考 vs 无参考”的区别再结合业务场景给出合理方案基本就能拿高分。答得差的一般是上来就写PSNR完全不考虑“没有原始视频”这个前提。另一个相关场景是视频内容审核如何用算法自动识别视频中的违规内容这类题通常围绕图像分类、目标检测、音频审核、文本审核等多模态技术展开还会涉及模型置信度阈值设置和人工审核兜底策略。答题时要体现“算法人工”的闭环思路而不是只谈模型结构。5. 常见问题与备赛经验实录5.1 笔试环境与代码提交的坑在线笔试题和本地刷题有个很大的区别提交代码不看你本地运行结果而是按照题目预先埋好的用例判分。很多人在本地IDE跑得好好的一提交就“通过率0%”大概率不是算法错了而是输入输出格式问题。我在这里栽过一次后来总结了一个必查清单确认是否使用标准输入输出Java的Scanner或BufferedReaderPython的input()如果题目说“多组输入”要看到EOF才停止。注意输出格式比如行末是否需要空格、浮点数保留几位小数。有一次我因为输出多了个空格直接判错。数组下标是否越界尤其是KMP、DP这类需要访问i-1的算法边界条件必须单独处理。是否误用了递归导致栈溢出。在线笔试环境通常限制递归深度深度超1e5的优先考虑改成迭代。代码中不要有调试输出比如System.out.println(debug)它会被当成正式输出的一部分。还有一个环境细节爱奇艺的在线编辑器不支持一些IDE傻瓜功能比如自动补全和代码格式化。建议提前在牛客网上用在线OJ练手熟悉“没有自动补全”的裸写环境。手写代码的速度和质量是笔试能不能拿高分的隐形分水岭。5.2 时间分配与检查策略我个人的做题顺序建议是先花2分钟扫一遍所有题目对难度有个预判然后按“选择题 → 简答题 → 编程题”的顺序推进。编程题里先做最有把握的那道哪怕它分值少先拿稳再做难题心态会稳很多。如果编程题做到一半卡住不要死磕超过15分钟。先把思路和关键代码写在纸上或者注释里然后去做后面的题目回头再补。在线笔试系统通常按最终提交的代码判分部分题还有“部分通过”的概念哪怕只能通过小数据也要提交有分总比空着强。选择题检查时要特别注意“下列说法错误的是”这类反向提问我见过太多人在这种题上踩坑明明会做结果因为没看清“错误”两个字选成了正确选项。建议读题时把“错误”“不正确”“不包括”这些关键词圈出来或者直接在草稿纸上写个大写的“错”字提醒自己。5.3 复盘方法把笔试变成能力提升的抓手笔试结束不等于事情结束复盘比考试本身更重要。我是这样做的考完当天趁记忆还热乎把所有题目和选项尽可能完整地回忆出来整理成一份错题集。一个星期后再重做一遍重点看那些“当时不会但看答案秒懂”的题因为它们暴露的是知识盲区而不是能力问题。复盘时不要只对答案要把每个题背后的知识点串起来。比如KMP的next数组和“字符串匹配”是一个知识簇可以连带复习Sunday算法、RK算法快速选择和快排是一个知识簇可以连带复习堆排序、归并排序的复杂度分析。当你形成这种“题→知识点簇”的映射刷题的效率会高很多。另外我会把错题按“概念模糊”“计算错误”“思路完全没方向”三个等级分类。概念模糊的靠重新看书解决计算错误的靠刷题提高敏感度思路没方向的题往往代表某个专题比如动态规划、概率统计没有建立系统框架需要专门拉出来补。5.4 关于“每天刷多少题”的建议很多准备校招的同学喜欢问“每天刷几道题才算够”。我的看法是数量不是关键关键是“有没有真的想明白”。如果一道题你只是看了一遍答案觉得懂了那考试时大概率还是不会写。真正的懂是能不看答案在15分钟内把代码完整写出来并且能说出每一步为什么这么写。我建议把刷题节奏分成两个阶段。第一个阶段按专题刷比如这周只刷动态规划下周只刷字符串匹配目标是建立每个专题的框架第二个阶段做混合刷题每天抽几道不同知识点的题模拟笔试的随机出题感觉。爱奇艺这套第二场笔试题非常适合作为第二阶段的开篇练手卷因为它覆盖的内容足够杂能帮你快速检验哪块知识还是漏洞。最后再说一个实际技巧碰到算法题时先用一句话写出你的算法思路和复杂度再动手写代码。比如“这题用动态规划定义dp[i]为以第i个元素结尾的最长递增子序列长度时间复杂度O(n^2)空间O(n)”。这个过程能帮你理清思路也能在代码写不完时向面试官/复盘时展示你的思维过程。笔试虽然是机器判分但这个习惯对之后的面试手写代码非常有帮助。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进